Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export interface ModelManifestProperty {
isCollection: boolean;
required: boolean;
writable: boolean;
resolveLanguage?: string;
resolveLiteral?: boolean;
relatedModel?: string;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/app-framework/src/shared/perspectiveHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export async function getModelManifest(perspective: PerspectiveProxy): Promise<M
isCollection: p.maxCount === undefined || p.maxCount > 1,
required: (p.minCount ?? 0) >= 1,
writable: p.writable ?? true,
...(p.resolveLanguage !== undefined && { resolveLanguage: p.resolveLanguage }),
...(p.resolveLiteral !== undefined && { resolveLiteral: p.resolveLiteral }),
...(p.class !== undefined && { relatedModel: shaclClassToLocalName(p.class) }),
}),
),
Expand Down
2 changes: 1 addition & 1 deletion packages/app-framework/src/shared/syncHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface SpaceSyncOptions {
/**
* Raw FileData for avatar/coverImage.
* Use when syncing after an image update so the target gets the same FileData
* written through its own resolveLanguage pipeline, rather than copying a
* written through its own file-storage pipeline, rather than copying a
* resolved data-URI string (which would be stored incorrectly).
*/
avatarData?: FileData;
Expand Down
17 changes: 9 additions & 8 deletions packages/block-system/shared/src/serialization.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { PerspectiveProxy } from '@coasys/ad4m';
import { Ad4mModel, getPropertiesMetadata } from '@coasys/ad4m';
import { FILE_STORAGE_LANGUAGE } from '@we/models';
import type { CollectionBlock, FileData } from '@we/models';

import { getBlockModel, getRegisteredBlockModels } from './registry';
Expand Down Expand Up @@ -146,7 +147,7 @@ function isFileData(value: unknown): value is FileData {

/**
* Walk a serialized block node tree, upload any FileData values on
* resolveLanguage properties to file-storage, and return a patched copy
* file-storage properties (resolveLiteral: false) and return a patched copy
* where those values are replaced with the resulting expression addresses
* (e.g. "QmLang://QmHash"). This keeps the editorState blob small (CIDs
* instead of raw base64 payloads) and ensures the AD4M model's create()
Expand All @@ -164,9 +165,9 @@ async function preUploadFileAssets(
if (ModelClass) {
const propsMeta = getPropertiesMetadata(ModelClass);
for (const [propName, meta] of Object.entries(propsMeta)) {
if (meta.resolveLanguage && isFileData(patched[propName])) {
if (meta.resolveLiteral === false && isFileData(patched[propName])) {
// Upload the file and replace the FileData with the expression address
const expressionAddress = await perspective.createExpression(patched[propName], meta.resolveLanguage);
const expressionAddress = await perspective.createExpression(patched[propName], FILE_STORAGE_LANGUAGE);
patched[propName] = expressionAddress;
}
}
Expand All @@ -189,7 +190,7 @@ async function preUploadFileAssets(

/**
* Walk a serialized block node tree and resolve any expression-address strings
* on resolveLanguage properties to data URIs via the perspective.
* on file-storage properties (resolveLiteral: false) to data URIs via the perspective.
* This is the read-side counterpart to preUploadFileAssets — called by
* BlockRenderer before loading the editorState blob into Lexical so that
* stored CIDs (e.g. "QmLang://QmHash") are replaced with renderable data URIs.
Expand All @@ -205,9 +206,9 @@ export async function resolveExpressionAddresses(
const propsMeta = getPropertiesMetadata(ModelClass);
for (const [propName, meta] of Object.entries(propsMeta)) {
const val = patched[propName];
// Only attempt resolution for resolveLanguage properties that hold a
// non-empty string containing "://" — the hallmark of an expression address.
if (meta.resolveLanguage && typeof val === 'string' && val.includes('://')) {
// Only attempt resolution for file-storage properties (resolveLiteral: false)
// that hold a non-empty string containing "://" — the hallmark of an expression address.
if (meta.resolveLiteral === false && typeof val === 'string' && val.includes('://')) {
try {
const expr = await perspective.getExpression(val);
if (expr?.data) {
Expand Down Expand Up @@ -275,7 +276,7 @@ export async function createBlocks(
// that FileData objects hit the deferred setProperty → createExpression →
// executeAction path, which stores clean URI references in the triple graph.
// (Passing pre-uploaded strings through initialValues → createSubject would
// JSON-encode them with quote characters, breaking resolveLanguage resolution.)
// JSON-encode them with quote characters, breaking file-storage resolution.)
const patchedNode = await preUploadFileAssets(perspective, node);

return Ad4mModel.transaction(perspective, async (tx) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/block-system/shared/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { SerializedBlockNode } from './types';

/**
* Decode an editorState data URL (returned by resolveLanguage) into a
* Decode an editorState data URL (returned by file-storage resolution) into a
* SerializedBlockNode (Lexical root node JSON).
*
* The ad4m model system resolves FILE_STORAGE_LANGUAGE CIDs into
Expand Down
3 changes: 1 addition & 2 deletions packages/models/src/blocks/AudioBlock.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { fileToDataUri, Flag, Model, Property } from '@coasys/ad4m';

import { FILE_STORAGE_LANGUAGE } from '../constants';
import { WeNode } from '../WeNode';

@Model({ name: 'AudioBlock' })
Expand All @@ -17,7 +16,7 @@ export class AudioBlock extends WeNode {
@Property({
through: 'we://audio_url',
required: true,
resolveLanguage: FILE_STORAGE_LANGUAGE,
resolveLiteral: false,
transform: fileToDataUri,
})
audioUrl: string = '';
Expand Down
3 changes: 1 addition & 2 deletions packages/models/src/blocks/CollectionBlock.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Flag, HasMany, HasManyMethods, Model, Property } from '@coasys/ad4m';

import { FILE_STORAGE_LANGUAGE } from '../constants';
import { WeNode } from '../WeNode';

@Model({ name: 'CollectionBlock' })
Expand All @@ -11,7 +10,7 @@ export class CollectionBlock extends WeNode {
@HasMany({ through: 'we://children' })
children: string[] = [];

@Property({ through: 'we://editor_state', resolveLanguage: FILE_STORAGE_LANGUAGE })
@Property({ through: 'we://editor_state', resolveLiteral: false })
editorState: string | null = null;

@Property({ through: 'we://type' })
Expand Down
3 changes: 1 addition & 2 deletions packages/models/src/blocks/FileBlock.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { fileToDataUri, Flag, Model, Property } from '@coasys/ad4m';

import { FILE_STORAGE_LANGUAGE } from '../constants';
import { WeNode } from '../WeNode';

@Model({ name: 'FileBlock' })
Expand All @@ -14,7 +13,7 @@ export class FileBlock extends WeNode {
@Property({ through: 'we://name', required: true })
name: string = '';

@Property({ through: 'we://url', required: true, resolveLanguage: FILE_STORAGE_LANGUAGE, transform: fileToDataUri })
@Property({ through: 'we://url', required: true, resolveLiteral: false, transform: fileToDataUri })
url: string = '';

@Property({ through: 'we://mime_type' })
Expand Down
3 changes: 1 addition & 2 deletions packages/models/src/blocks/ImageBlock.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { fileToDataUri, Flag, Model, Property } from '@coasys/ad4m';

import { FILE_STORAGE_LANGUAGE } from '../constants';
import { WeNode } from '../WeNode';

@Model({ name: 'ImageBlock' })
export class ImageBlock extends WeNode {
@Flag({ through: 'we://flag', value: 'we://image_block' })
flag: string = '';

@Property({ through: 'we://src', required: true, resolveLanguage: FILE_STORAGE_LANGUAGE, transform: fileToDataUri })
@Property({ through: 'we://src', required: true, resolveLiteral: false, transform: fileToDataUri })
src: string = '';

@Property({ through: 'we://altText' })
Expand Down
5 changes: 2 additions & 3 deletions packages/models/src/entities/Space.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { fileToDataUri, Flag, HasOne, Model, Property } from '@coasys/ad4m';

import { LocationBlock } from '../blocks/LocationBlock';
import { FILE_STORAGE_LANGUAGE } from '../constants';
import { WeNode } from '../WeNode';

@Model({ name: 'Space' })
Expand All @@ -27,10 +26,10 @@ export class Space extends WeNode {
@Property({ through: 'we://discovery' })
discovery: string = 'hidden';

@Property({ through: 'we://image', resolveLanguage: FILE_STORAGE_LANGUAGE, transform: fileToDataUri })
@Property({ through: 'we://image', resolveLiteral: false, transform: fileToDataUri })
avatar?: string;

@Property({ through: 'we://thumbnail', resolveLanguage: FILE_STORAGE_LANGUAGE, transform: fileToDataUri })
@Property({ through: 'we://thumbnail', resolveLiteral: false, transform: fileToDataUri })
coverImage?: string;

@HasOne(() => LocationBlock, { through: 'we://location' })
Expand Down
3 changes: 1 addition & 2 deletions packages/models/src/entities/Template.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Flag, HasMany, HasManyMethods, Model, Property } from '@coasys/ad4m';

import { FILE_STORAGE_LANGUAGE } from '../constants';
import { WeNode } from '../WeNode';
import { ChatSession } from './ChatSession';

Expand All @@ -20,7 +19,7 @@ export class Template extends WeNode {

@Property({
through: 'we://template_schema',
resolveLanguage: FILE_STORAGE_LANGUAGE,
resolveLiteral: false,
})
schema: string | null = null;

Expand Down
5 changes: 2 additions & 3 deletions packages/models/src/entities/Theme.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Flag, Model, Property } from '@coasys/ad4m';

import { FILE_STORAGE_LANGUAGE } from '../constants';
import { WeNode } from '../WeNode';

@Model({ name: 'Theme' })
Expand All @@ -23,14 +22,14 @@ export class Theme extends WeNode {
/** Raw CSS string (e.g. [data-we-theme='x'] { ... } rules, ::part() selectors, etc.) */
@Property({
through: 'we://stylesheet',
resolveLanguage: FILE_STORAGE_LANGUAGE,
resolveLiteral: false,
})
css: string | null = null;

/** Structured token overrides (primaryHue, saturation, neutralSaturation, etc.) */
@Property({
through: 'we://token_overrides',
resolveLanguage: FILE_STORAGE_LANGUAGE,
resolveLiteral: false,
})
overrides: string | null = null;
}
2 changes: 1 addition & 1 deletion packages/models/src/utils/fileTransforms.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** Decode a file-storage resolved value into a plain string.
* resolveLanguage always converts stored blobs to "data:<mime>;base64,<b64>" strings. */
* File-storage properties (resolveLiteral: false) convert stored blobs to "data:<mime>;base64,<b64>" strings. */
export function decodeFileAsString(data: string | null | undefined): string {
if (typeof data !== 'string' || !data.startsWith('data:') || !data.includes(';base64,')) return '';
try {
Expand Down
2 changes: 1 addition & 1 deletion packages/models/src/utils/imageHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export async function readFileAsFileData(file: File): Promise<FileData> {
/**
* Reconstruct a FileData value object from a resolved data URI string.
*
* After AgentProfile.findOne() / Space.findOne() the resolveLanguage transform
* After Space.findOne() the file-storage (resolveLiteral: false) transform
* converts stored FileData objects to `data:<mime>;base64,<b64>` strings.
* This function reverses that transform so the value can be safely passed back
* through FILE_STORAGE_LANGUAGE — the storage is content-addressed
Expand Down