Add live field provenance for React components
This commit is contained in:
@@ -15,11 +15,13 @@ import {
|
||||
import {
|
||||
CaminoService,
|
||||
CrdtValueSchema,
|
||||
FieldValueSourceSchema,
|
||||
ListValueSchema,
|
||||
NullValueSchema,
|
||||
ObjectValueSchema,
|
||||
RefValueSchema,
|
||||
ValueSchema,
|
||||
ValueSourceSchema,
|
||||
type Value,
|
||||
} from "./camino/api_pb.js";
|
||||
import {
|
||||
@@ -181,6 +183,44 @@ export type Field<T> = {
|
||||
set(value: T): Promise<void>;
|
||||
};
|
||||
|
||||
export type LiveFieldValue<T> = {
|
||||
$caminoValue: T;
|
||||
$caminoSource: {
|
||||
field: {
|
||||
objectId: string;
|
||||
fieldName: string;
|
||||
fieldType?: string;
|
||||
fieldStorage?: string;
|
||||
conflictStrategy?: string;
|
||||
revision?: number | string | bigint;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export const liveFieldValue = <T>(params: {
|
||||
value: T;
|
||||
objectId: string;
|
||||
fieldName: string;
|
||||
fieldType?: string;
|
||||
fieldStorage?: string;
|
||||
conflictStrategy?: string;
|
||||
revision?: number | string | bigint;
|
||||
}): LiveFieldValue<T> => ({
|
||||
$caminoValue: params.value,
|
||||
$caminoSource: {
|
||||
field: {
|
||||
objectId: params.objectId,
|
||||
fieldName: params.fieldName,
|
||||
...(params.fieldType ? { fieldType: params.fieldType } : {}),
|
||||
...(params.fieldStorage ? { fieldStorage: params.fieldStorage } : {}),
|
||||
...(params.conflictStrategy
|
||||
? { conflictStrategy: params.conflictStrategy }
|
||||
: {}),
|
||||
...(params.revision !== undefined ? { revision: params.revision } : {}),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export type RuntimeHandler<Context> = (
|
||||
context: Context,
|
||||
) => Promise<unknown> | unknown;
|
||||
@@ -429,6 +469,43 @@ const bytesToBase64 = (value: Uint8Array) =>
|
||||
|
||||
const base64ToBytes = (value: string) => Buffer.from(value, "base64");
|
||||
|
||||
const sourceToProto = (value: unknown) => {
|
||||
if (!isRecord(value) || !isRecord(value.field)) {
|
||||
return undefined;
|
||||
}
|
||||
const field = value.field;
|
||||
if (
|
||||
typeof field.objectId !== "string" ||
|
||||
typeof field.fieldName !== "string"
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return create(ValueSourceSchema, {
|
||||
field: create(FieldValueSourceSchema, {
|
||||
objectId: field.objectId,
|
||||
fieldName: field.fieldName,
|
||||
fieldType: typeof field.fieldType === "string" ? field.fieldType : "",
|
||||
fieldStorage:
|
||||
typeof field.fieldStorage === "string" ? field.fieldStorage : "",
|
||||
conflictStrategy:
|
||||
typeof field.conflictStrategy === "string" ? field.conflictStrategy : "",
|
||||
revision:
|
||||
typeof field.revision === "bigint"
|
||||
? field.revision
|
||||
: typeof field.revision === "number"
|
||||
? BigInt(field.revision)
|
||||
: typeof field.revision === "string" && /^\d+$/.test(field.revision)
|
||||
? BigInt(field.revision)
|
||||
: 0n,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
const withSource = (value: Value, source: unknown): Value => {
|
||||
const sourceValue = sourceToProto(source);
|
||||
return sourceValue ? create(ValueSchema, { ...value, source: sourceValue }) : value;
|
||||
};
|
||||
|
||||
export const jsToProtoValue = (value: unknown): Value => {
|
||||
if (value === null || value === undefined) {
|
||||
return create(ValueSchema, {
|
||||
@@ -474,6 +551,9 @@ export const jsToProtoValue = (value: unknown): Value => {
|
||||
});
|
||||
}
|
||||
if (isRecord(value)) {
|
||||
if (Object.hasOwn(value, "$caminoValue") && isRecord(value.$caminoSource)) {
|
||||
return withSource(jsToProtoValue(value.$caminoValue), value.$caminoSource);
|
||||
}
|
||||
if (typeof value.$caminoRef === "string") {
|
||||
return create(ValueSchema, {
|
||||
kind: {
|
||||
|
||||
Reference in New Issue
Block a user