@dxos/plugin-file 0.11.0 → 0.12.0-next-bbabc02363f18d7643ea4160e3a7a7809870fd0d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/lib/FileCapabilities.mjs +22 -0
  2. package/dist/lib/FileCapabilities.mjs.map +1 -0
  3. package/dist/lib/FileEvents.mjs +15 -0
  4. package/dist/lib/FileEvents.mjs.map +1 -0
  5. package/dist/lib/FileLimits.mjs +31 -0
  6. package/dist/lib/FileLimits.mjs.map +1 -0
  7. package/dist/lib/FileOperation.mjs +39 -0
  8. package/dist/lib/FileOperation.mjs.map +1 -0
  9. package/dist/lib/FilePlugin.mjs +5 -23
  10. package/dist/lib/FilePlugin.mjs.map +1 -1
  11. package/dist/lib/FilePlugin.node.mjs +5 -5
  12. package/dist/lib/FilePlugin.node.mjs.map +1 -1
  13. package/dist/lib/Settings.mjs +16 -0
  14. package/dist/lib/Settings.mjs.map +1 -0
  15. package/dist/lib/capabilities/node.mjs +20 -4
  16. package/dist/lib/capabilities/node.mjs.map +1 -1
  17. package/dist/lib/capabilities.mjs +42 -10
  18. package/dist/lib/capabilities.mjs.map +1 -1
  19. package/dist/lib/chunk-FileArticle.mjs.map +1 -1
  20. package/dist/lib/chunk-create-object.mjs +9 -6
  21. package/dist/lib/chunk-create-object.mjs.map +1 -1
  22. package/dist/lib/chunk-create.mjs +7 -3
  23. package/dist/lib/chunk-create.mjs.map +1 -1
  24. package/dist/lib/chunk-edge-backend.mjs +7 -5
  25. package/dist/lib/chunk-edge-backend.mjs.map +1 -1
  26. package/dist/lib/chunk-file-uploader.mjs +7 -7
  27. package/dist/lib/chunk-file-uploader.mjs.map +1 -1
  28. package/dist/lib/chunk-inline-backend.mjs +3 -3
  29. package/dist/lib/chunk-inline-backend.mjs.map +1 -1
  30. package/dist/lib/chunk-markdown-extension.mjs +4 -4
  31. package/dist/lib/chunk-markdown-extension.mjs.map +1 -1
  32. package/dist/lib/chunk-meta.mjs +2 -2
  33. package/dist/lib/chunk-meta.mjs.map +1 -1
  34. package/dist/lib/chunk-operation-handler.mjs +3 -2
  35. package/dist/lib/chunk-operation-handler.mjs.map +1 -1
  36. package/dist/lib/chunk-react-surface.mjs +5 -3
  37. package/dist/lib/chunk-react-surface.mjs.map +1 -1
  38. package/dist/lib/chunk-read.mjs +3 -3
  39. package/dist/lib/chunk-read.mjs.map +1 -1
  40. package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
  41. package/dist/lib/chunk-settings.mjs +7 -6
  42. package/dist/lib/chunk-settings.mjs.map +1 -1
  43. package/dist/lib/chunk-skill-definition.mjs +3 -3
  44. package/dist/lib/chunk-skill-definition.mjs.map +1 -1
  45. package/dist/lib/chunk-skills.mjs +3 -2
  46. package/dist/lib/chunk-skills.mjs.map +1 -1
  47. package/dist/lib/components.mjs +1 -1
  48. package/dist/lib/components.mjs.map +1 -1
  49. package/dist/lib/containers.mjs +5 -4
  50. package/dist/lib/containers.mjs.map +1 -1
  51. package/dist/lib/index.mjs +7 -3
  52. package/dist/lib/operations.mjs +4 -2
  53. package/dist/lib/operations.mjs.map +1 -1
  54. package/dist/lib/plugin.mjs +2 -3
  55. package/dist/lib/plugin.mjs.map +1 -1
  56. package/dist/lib/translations.mjs +1 -1
  57. package/dist/lib/translations.mjs.map +1 -1
  58. package/dist/types/src/FilePlugin.d.ts +1 -1
  59. package/dist/types/src/FilePlugin.d.ts.map +1 -1
  60. package/dist/types/src/FilePlugin.node.d.ts +1 -1
  61. package/dist/types/src/FilePlugin.node.d.ts.map +1 -1
  62. package/dist/types/src/capabilities/create-object.d.ts +2 -2
  63. package/dist/types/src/capabilities/create-object.d.ts.map +1 -1
  64. package/dist/types/src/capabilities/edge-backend.d.ts +2 -2
  65. package/dist/types/src/capabilities/edge-backend.d.ts.map +1 -1
  66. package/dist/types/src/capabilities/file-uploader.d.ts +2 -2
  67. package/dist/types/src/capabilities/file-uploader.d.ts.map +1 -1
  68. package/dist/types/src/capabilities/index.d.ts +10 -11
  69. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  70. package/dist/types/src/capabilities/inline-backend.d.ts +3 -3
  71. package/dist/types/src/capabilities/inline-backend.d.ts.map +1 -1
  72. package/dist/types/src/capabilities/markdown-extension.d.ts +2 -2
  73. package/dist/types/src/capabilities/markdown-extension.d.ts.map +1 -1
  74. package/dist/types/src/capabilities/node.d.ts +6 -4
  75. package/dist/types/src/capabilities/node.d.ts.map +1 -1
  76. package/dist/types/src/capabilities/operation-handler.d.ts +2 -3
  77. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/react-surface.d.ts +2 -2
  79. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  80. package/dist/types/src/capabilities/settings.d.ts +2 -2
  81. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  82. package/dist/types/src/capabilities/skill-definition.d.ts +2 -2
  83. package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -1
  84. package/dist/types/src/components/FileInput/FileInput.d.ts.map +1 -1
  85. package/dist/types/src/containers/FileArticle/FileArticle.d.ts +1 -1
  86. package/dist/types/src/containers/FileArticle/FileArticle.d.ts.map +1 -1
  87. package/dist/types/src/containers/FileSettings/FileSettings.d.ts.map +1 -1
  88. package/dist/types/src/extensions/image.d.ts.map +1 -1
  89. package/dist/types/src/index.d.ts +6 -2
  90. package/dist/types/src/index.d.ts.map +1 -1
  91. package/dist/types/src/operations/create.d.ts +3 -3
  92. package/dist/types/src/operations/create.d.ts.map +1 -1
  93. package/dist/types/src/operations/index.d.ts +1 -1
  94. package/dist/types/src/operations/index.d.ts.map +1 -1
  95. package/dist/types/src/operations/read.d.ts +2 -2
  96. package/dist/types/src/operations/read.d.ts.map +1 -1
  97. package/dist/types/src/plugin.d.ts +1 -2
  98. package/dist/types/src/plugin.d.ts.map +1 -1
  99. package/dist/types/src/skills/file-skill.d.ts +1 -1
  100. package/dist/types/src/skills/file-skill.d.ts.map +1 -1
  101. package/dist/types/src/types/FileCapabilities.d.ts +11 -3
  102. package/dist/types/src/types/FileCapabilities.d.ts.map +1 -1
  103. package/dist/types/src/types/FileEvents.d.ts +8 -0
  104. package/dist/types/src/types/FileEvents.d.ts.map +1 -0
  105. package/dist/types/src/types/{limits.d.ts → FileLimits.d.ts} +1 -1
  106. package/dist/types/src/types/FileLimits.d.ts.map +1 -0
  107. package/dist/types/src/types/FileOperation.d.ts +2 -2
  108. package/dist/types/src/types/FileOperation.d.ts.map +1 -1
  109. package/dist/types/tsconfig.tsbuildinfo +1 -1
  110. package/package.json +65 -31
  111. package/src/FilePlugin.node.ts +10 -7
  112. package/src/FilePlugin.test.ts +2 -2
  113. package/src/FilePlugin.tsx +22 -35
  114. package/src/capabilities/create-object.ts +9 -6
  115. package/src/capabilities/edge-backend.ts +10 -6
  116. package/src/capabilities/file-uploader.ts +6 -6
  117. package/src/capabilities/index.ts +51 -13
  118. package/src/capabilities/inline-backend.ts +3 -3
  119. package/src/capabilities/markdown-extension.ts +4 -4
  120. package/src/capabilities/node.ts +29 -9
  121. package/src/capabilities/operation-handler.ts +4 -4
  122. package/src/capabilities/react-surface.ts +5 -3
  123. package/src/capabilities/settings.ts +7 -5
  124. package/src/capabilities/skill-definition.ts +3 -3
  125. package/src/components/FileInput/FileInput.tsx +6 -2
  126. package/src/containers/FileArticle/FileArticle.tsx +1 -1
  127. package/src/containers/FileSettings/FileSettings.tsx +3 -1
  128. package/src/extensions/image.tsx +1 -2
  129. package/src/index.ts +6 -2
  130. package/src/meta.ts +1 -1
  131. package/src/operations/create.test.ts +20 -18
  132. package/src/operations/create.ts +9 -4
  133. package/src/operations/index.ts +8 -5
  134. package/src/operations/read.ts +2 -2
  135. package/src/plugin.ts +1 -3
  136. package/src/skills/file-skill.ts +3 -2
  137. package/src/translations.ts +1 -1
  138. package/src/types/FileCapabilities.ts +18 -5
  139. package/src/types/FileEvents.ts +16 -0
  140. package/src/types/FileOperation.ts +4 -4
  141. package/dist/lib/chunk-types.mjs +0 -98
  142. package/dist/lib/chunk-types.mjs.map +0 -1
  143. package/dist/lib/types.mjs +0 -2
  144. package/dist/types/src/types/index.d.ts +0 -7
  145. package/dist/types/src/types/index.d.ts.map +0 -1
  146. package/dist/types/src/types/limits.d.ts.map +0 -1
  147. package/dist/types/src/types/types.d.ts +0 -9
  148. package/dist/types/src/types/types.d.ts.map +0 -1
  149. package/src/types/index.ts +0 -12
  150. package/src/types/types.ts +0 -21
  151. /package/src/types/{limits.ts → FileLimits.ts} +0 -0
@@ -0,0 +1,22 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import { ACCEPTED_MIME } from "./FileLimits.mjs";
3
+ import * as Schema from "effect/Schema";
4
+ import * as Capability from "@dxos/app-framework/Capability";
5
+ import { meta } from "#meta";
6
+ //#region src/types/FileCapabilities.ts
7
+ var FileCapabilities_exports = /* @__PURE__ */ __exportAll({
8
+ Backend: () => Backend,
9
+ FileAction: () => FileAction,
10
+ SettingsAtom: () => SettingsAtom
11
+ });
12
+ var Backend = Capability.make()(`${meta.profile.key}.capability.backend`);
13
+ var SettingsAtom = Capability.makeSingleton()(`${meta.profile.key}.capability.settings`);
14
+ var FileAction;
15
+ (function(_FileAction) {
16
+ const UploadAnnotationId = _FileAction.UploadAnnotationId = Symbol.for(`${meta.profile.key}.annotation.upload`);
17
+ _FileAction.CreateFileSchema = Schema.Struct({ file: Schema.instanceOf(File).annotations({ [UploadAnnotationId]: ACCEPTED_MIME }) });
18
+ })(FileAction || (FileAction = {}));
19
+ //#endregion
20
+ export { Backend, FileAction, SettingsAtom, FileCapabilities_exports as t };
21
+
22
+ //# sourceMappingURL=FileCapabilities.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileCapabilities.mjs","names":[],"sources":["../../src/types/FileCapabilities.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Atom } from '@effect-atom/atom';\nimport * as Schema from 'effect/Schema';\n\nimport * as Capability from '@dxos/app-framework/Capability';\n\nimport { meta } from '#meta';\n\nimport { ACCEPTED_MIME } from './FileLimits';\nimport * as Settings from './Settings';\n\n/**\n * Descriptor for a registered `BlobBackend` storage option, surfaced in the file plugin's\n * settings UI. Actual upload/read logic lives in the Blob backend registered on the Hypergraph\n * under `storage` (see `client.graph.registerBlobBackend`) — this type carries no behavior.\n */\nexport type Backend = {\n /** Display label shown in the settings UI. */\n readonly name: string;\n /** Description shown next to the backend in settings. */\n readonly description?: string;\n /**\n * `Blob.fromBytes`'s `storage` option to use when this backend is selected. Also the settings\n * key identifying this backend — one `BlobBackend` is registered per storage name, so the two\n * concepts always coincide.\n */\n readonly storage: string;\n};\n\n// Multi capability: inline-backend and edge-backend each contribute one entry.\nexport const Backend = Capability.make<Backend>()(`${meta.profile.key}.capability.backend`);\n\nexport const SettingsAtom = Capability.makeSingleton<Atom.Writable<Settings.Settings>>()(\n `${meta.profile.key}.capability.settings`,\n);\n\nexport namespace FileAction {\n export const UploadAnnotationId = Symbol.for(`${meta.profile.key}.annotation.upload`);\n\n export const CreateFileSchema = Schema.Struct({\n file: Schema.instanceOf(File).annotations({\n [UploadAnnotationId]: ACCEPTED_MIME,\n }),\n });\n\n export type CreateFileForm = Schema.Schema.Type<typeof CreateFileSchema>;\n}\n"],"mappings":";;;;;;;;;;;AAiCA,IAAa,UAAU,WAAW,KAAc,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,oBAAoB;AAE1F,IAAa,eAAe,WAAW,cAAgD,CAAC,CACtF,GAAG,KAAK,QAAQ,IAAI,qBACtB;AAEO,IAAA;;CACE,MAAM,qBAAA,YAAA,qBAAqB,OAAO,IAAI,GAAG,KAAK,QAAQ,IAAI,mBAAmB;CAEvE,YAAA,mBAAmB,OAAO,OAAO,EAC5C,MAAM,OAAO,WAAW,IAAI,CAAC,CAAC,YAAY,GACvC,qBAAqB,cACxB,CAAC,EACH,CAAC;GAGH,eAAA,aAAA,CAAA,EAAA"}
@@ -0,0 +1,15 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import { meta } from "#meta";
3
+ import * as ActivationEvent from "@dxos/app-framework/ActivationEvent";
4
+ //#region src/types/FileEvents.ts
5
+ var FileEvents_exports = /* @__PURE__ */ __exportAll({ Start: () => Start });
6
+ /**
7
+ * The feature's start event: the plugin's start-gated modules (and cross-plugin
8
+ * contributions consumed by this feature) activate here. Fired on demand and by the
9
+ * host's idle trickle.
10
+ */
11
+ var Start = ActivationEvent.pluginStart(meta.profile.key);
12
+ //#endregion
13
+ export { Start, FileEvents_exports as t };
14
+
15
+ //# sourceMappingURL=FileEvents.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileEvents.mjs","names":[],"sources":["../../src/types/FileEvents.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as ActivationEvent from '@dxos/app-framework/ActivationEvent';\n\nimport { meta } from '#meta';\n\n/**\n * The feature's start event: the plugin's start-gated modules (and cross-plugin\n * contributions consumed by this feature) activate here. Fired on demand and by the\n * host's idle trickle.\n */\nexport const Start = ActivationEvent.pluginStart(meta.profile.key);\n"],"mappings":";;;;;;;;;;AAeA,IAAa,QAAQ,gBAAgB,YAAY,KAAK,QAAQ,GAAG"}
@@ -0,0 +1,31 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ //#region src/types/FileLimits.ts
3
+ var FileLimits_exports = /* @__PURE__ */ __exportAll({
4
+ ACCEPTED_MIME: () => ACCEPTED_MIME,
5
+ isAcceptedMimeType: () => isAcceptedMimeType
6
+ });
7
+ var ACCEPTED_MIME = {
8
+ "image/*": [
9
+ ".jpg",
10
+ ".jpeg",
11
+ ".png",
12
+ ".gif",
13
+ ".webp",
14
+ ".svg"
15
+ ],
16
+ "video/*": [
17
+ ".mp4",
18
+ ".webm",
19
+ ".mov"
20
+ ],
21
+ "application/pdf": [".pdf"]
22
+ };
23
+ var isAcceptedMimeType = (type) => {
24
+ if (type === "application/pdf") return true;
25
+ if (type.startsWith("image/") || type.startsWith("video/")) return true;
26
+ return false;
27
+ };
28
+ //#endregion
29
+ export { ACCEPTED_MIME, isAcceptedMimeType, FileLimits_exports as t };
30
+
31
+ //# sourceMappingURL=FileLimits.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileLimits.mjs","names":[],"sources":["../../src/types/FileLimits.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nexport const ACCEPTED_MIME: Record<string, string[]> = {\n 'image/*': ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg'],\n 'video/*': ['.mp4', '.webm', '.mov'],\n 'application/pdf': ['.pdf'],\n};\n\nexport const isAcceptedMimeType = (type: string): boolean => {\n if (type === 'application/pdf') {\n return true;\n }\n if (type.startsWith('image/') || type.startsWith('video/')) {\n return true;\n }\n return false;\n};\n"],"mappings":";;;;;;AAIA,IAAa,gBAA0C;CACrD,WAAW;EAAC;EAAQ;EAAS;EAAQ;EAAQ;EAAS;CAAM;CAC5D,WAAW;EAAC;EAAQ;EAAS;CAAM;CACnC,mBAAmB,CAAC,MAAM;AAC5B;AAEA,IAAa,sBAAsB,SAA0B;CAC3D,IAAI,SAAS,mBACX,OAAO;CAET,IAAI,KAAK,WAAW,QAAQ,KAAK,KAAK,WAAW,QAAQ,GACvD,OAAO;CAET,OAAO;AACT"}
@@ -0,0 +1,39 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import { FileAction } from "./FileCapabilities.mjs";
3
+ import * as Schema from "effect/Schema";
4
+ import * as Capability from "@dxos/app-framework/Capability";
5
+ import { meta } from "#meta";
6
+ import * as Operation from "@dxos/compute/Operation";
7
+ import { DXN, Database, Ref, Type } from "@dxos/echo";
8
+ import { ContentBlock, File } from "@dxos/types";
9
+ //#region src/types/FileOperation.ts
10
+ var FileOperation_exports = /* @__PURE__ */ __exportAll({
11
+ Create: () => Create,
12
+ Read: () => Read
13
+ });
14
+ var makeKey = (name) => DXN.make(`${meta.profile.key}.operation.${name}`);
15
+ var Create = Operation.make({
16
+ meta: {
17
+ key: makeKey("create"),
18
+ name: "Create File",
19
+ icon: "ph--file--regular"
20
+ },
21
+ services: [Capability.Service],
22
+ input: Schema.extend(FileAction.CreateFileSchema, Schema.Struct({ db: Database.Database })),
23
+ output: Schema.Struct({ object: Type.getSchema(File.File) })
24
+ });
25
+ var Read = Operation.make({
26
+ meta: {
27
+ key: makeKey("read"),
28
+ name: "Read File",
29
+ description: "Reads the contents of a file and returns them as a File content block (data URL for inline files, original URL for external files).",
30
+ icon: "ph--file-arrow-down--regular"
31
+ },
32
+ input: Schema.Struct({ file: Ref.Ref(File.File).annotations({ description: "The file to read." }) }),
33
+ output: ContentBlock.ContentBlockResult,
34
+ services: [Database.Service]
35
+ });
36
+ //#endregion
37
+ export { Create, Read, FileOperation_exports as t };
38
+
39
+ //# sourceMappingURL=FileOperation.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileOperation.mjs","names":[],"sources":["../../src/types/FileOperation.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, DXN, Ref, Type } from '@dxos/echo';\nimport { ContentBlock, File } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nimport * as FileCapabilities from './FileCapabilities';\n\nconst makeKey = (name: string) => DXN.make(`${meta.profile.key}.operation.${name}`);\n\nexport const Create = Operation.make({\n meta: { key: makeKey('create'), name: 'Create File', icon: 'ph--file--regular' },\n services: [Capability.Service],\n input: Schema.extend(FileCapabilities.FileAction.CreateFileSchema, Schema.Struct({ db: Database.Database })),\n output: Schema.Struct({\n object: Type.getSchema(File.File),\n }),\n});\n\nexport const Read = Operation.make({\n meta: {\n key: makeKey('read'),\n name: 'Read File',\n description:\n 'Reads the contents of a file and returns them as a File content block (data URL for inline files, original URL for external files).',\n icon: 'ph--file-arrow-down--regular',\n },\n input: Schema.Struct({\n file: Ref.Ref(File.File).annotations({\n description: 'The file to read.',\n }),\n }),\n output: ContentBlock.ContentBlockResult,\n services: [Database.Service],\n});\n"],"mappings":";;;;;;;;;;;;;AAiBA,IAAM,WAAW,SAAiB,IAAI,KAAK,GAAG,KAAK,QAAQ,IAAI,aAAa,MAAM;AAElF,IAAa,SAAS,UAAU,KAAK;CACnC,MAAM;EAAE,KAAK,QAAQ,QAAQ;EAAG,MAAM;EAAe,MAAM;CAAoB;CAC/E,UAAU,CAAC,WAAW,OAAO;CAC7B,OAAO,OAAO,OAAA,WAAmC,kBAAkB,OAAO,OAAO,EAAE,IAAI,SAAS,SAAS,CAAC,CAAC;CAC3G,QAAQ,OAAO,OAAO,EACpB,QAAQ,KAAK,UAAU,KAAK,IAAI,EAClC,CAAC;AACH,CAAC;AAED,IAAa,OAAO,UAAU,KAAK;CACjC,MAAM;EACJ,KAAK,QAAQ,MAAM;EACnB,MAAM;EACN,aACE;EACF,MAAM;CACR;CACA,OAAO,OAAO,OAAO,EACnB,MAAM,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,YAAY,EACnC,aAAa,oBACf,CAAC,EACH,CAAC;CACD,QAAQ,aAAa;CACrB,UAAU,CAAC,SAAS,OAAO;AAC7B,CAAC"}
@@ -1,36 +1,18 @@
1
1
  import { meta } from "#meta";
2
- import { Plugin } from "@dxos/app-framework";
3
2
  import { Blob } from "@dxos/echo";
4
- import { AppActivationEvents, AppPlugin } from "@dxos/app-toolkit";
5
- import { ClientEvents } from "@dxos/plugin-client";
6
- import { MarkdownEvents } from "@dxos/plugin-markdown";
3
+ import { File } from "@dxos/types";
4
+ import * as Plugin from "@dxos/app-framework/Plugin";
5
+ import * as AppCapability from "@dxos/app-toolkit/AppCapability";
7
6
  import { CreateObject, EdgeBackend, FileUploader, InlineBackend, Markdown, OperationHandler, ReactSurface, Settings, SkillDefinition } from "#capabilities";
8
7
  import { translations } from "#translations";
9
- import { File } from "#types";
10
8
  //#endregion
11
9
  //#region src/FilePlugin.tsx
12
- var FilePlugin = Plugin.define(meta).pipe(AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }), AppPlugin.addCreateObjectModule({ activate: CreateObject }), AppPlugin.addOperationHandlerModule({ activate: OperationHandler }), AppPlugin.addSchemaModule({ schema: [File.File, Blob.Blob] }), AppPlugin.addSettingsModule({ activate: Settings }), AppPlugin.addSurfaceModule({ activate: ReactSurface }), AppPlugin.addTranslationsModule({ translations }), Plugin.addModule({
13
- id: "inline-backend",
14
- activatesOn: AppActivationEvents.SetupSchema,
15
- activate: InlineBackend
16
- }), Plugin.addModule({
17
- id: "file-uploader",
18
- activatesOn: ClientEvents.ClientReady,
19
- activate: FileUploader
20
- }), Plugin.addModule({
21
- id: "edge-backend",
22
- activatesOn: ClientEvents.ClientReady,
23
- activate: EdgeBackend
24
- }), Plugin.addModule({
25
- id: "markdown",
26
- activatesOn: MarkdownEvents.SetupExtensions,
27
- activate: Markdown
28
- }), AppPlugin.addPluginAssetModule({ asset: {
10
+ var FilePlugin = Plugin.define(meta).pipe(Plugin.addModule(SkillDefinition), Plugin.addModule(CreateObject), Plugin.addModule(OperationHandler), Plugin.addModule(AppCapability.schema([File.File, Blob.Blob])), Plugin.addModule(Settings), Plugin.addModule(ReactSurface), Plugin.addModule(AppCapability.translations(translations)), Plugin.addModule(InlineBackend), Plugin.addModule(FileUploader), Plugin.addModule(EdgeBackend), Plugin.addModule(Markdown), Plugin.addModule(AppCapability.pluginAsset({
29
11
  pluginId: meta.profile.key,
30
12
  path: "PLUGIN.mdl",
31
13
  content: "---\nid: org.dxos.plugin.file\nname: FilePlugin\nversion: 0.2.0\n---\n\nFilePlugin enables DXOS Composer to store and preview binary files — images, videos, and PDFs — as first-class ECHO objects.\nA File object's `data` field is a reference to a `Blob` ECHO object (defined in `@dxos/echo`), which abstracts where the\nbytes actually live and how they're read. Uploads are routed through a pluggable storage system: the built-in `inline`\nstorage embeds bytes on the Blob object itself, while external storage (e.g. WNFS, edge) can be contributed by other\nplugins by registering a `BlobBackend` on the ECHO Hypergraph. `Blob.url`/`Blob.read` resolve a renderable URL or raw\nbytes uniformly regardless of backend, so the File schema and preview surfaces stay backend-agnostic without a\ndedicated URL-resolver capability.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n\n## Types\n\n```mdl\ntype File\n desc: ECHO object (typename org.dxos.type.file, version 0.2.0) representing an uploaded binary asset.\n fields:\n name?: string\n type: string # MIME type\n size: number # byte count\n data: Ref<Blob> # reference to a Blob object (org.dxos.type.blob, defined in @dxos/echo)\n timestamp?: string # ISO 8601 upload time\n```\n\n```mdl\ntype BackendDescriptor\n desc: |\n UI-facing descriptor for a registered storage option. Carries no upload/read behavior itself —\n that lives in the matching `BlobBackend` registered on the ECHO Hypergraph under `storage`.\n fields:\n name: string # display label shown in settings\n description?: string # description shown next to the backend in settings\n storage: string # Blob.fromBytes's `storage` option; also the settings key (e.g. 'inline', 'wnfs', 'edge')\n```\n\n```mdl\ntype Settings\n desc: Per-user plugin settings stored in the ECHO space.\n fields:\n backend?: string # active backend's storage name; defaults to 'inline'\n```\n\n## Components\n\n```mdl\ncomponent FilePreview\n desc: |\n Renders a File object using the appropriate HTML element for its MIME type.\n Images use <img>, videos use <video controls>, PDFs use <iframe>, and\n all other types fall back to a download link.\n props:\n type: string # MIME type\n url: string # renderable data:, blob:, or http(s): URL\n layout: |\n ┌──────────────────────────────┐\n │ <img> / <video> / <iframe> │\n │ or [Download file] link │\n └──────────────────────────────┘\n```\n\n```mdl\ncomponent FileInput\n desc: Drag-and-drop / browse file picker used inside the Create Object form.\n props:\n schema: Schema # effect/Schema with UploadAnnotation on the file field\n emits:\n onChange(file: File)\n layout: |\n ┌──────────────────────────────┐\n │ [ Drop file or click here ] │\n └──────────────────────────────┘\n```\n\n```mdl\ncomponent FileSettings\n desc: Plugin settings panel rendered in the Composer settings surface.\n props:\n settings: Settings\n emits:\n onSettingsChange(settings: Settings)\n layout: |\n ┌──────────────────────────────┐\n │ Storage backend: [select ▼] │\n │ (one row per registered │\n │ BackendDescriptor) │\n └──────────────────────────────┘\n```\n\n```mdl\ncomponent FileArticle\n desc: |\n Full-viewport article container rendered for article, section, and slide\n roles. Loads the File's referenced Blob and resolves a renderable URL via\n Blob.url; if the backend has no getUrl, falls back to Blob.read and\n constructs a blob: object URL (revoked on unmount). Delegates to\n FilePreview. Shows an empty state while the URL is resolving or if the\n File is not attached to a database.\n props:\n role: AppSurface.Role\n subject: File\n layout: |\n ┌──────────────────────────────┐\n │ │\n │ FilePreview │\n │ (fills container) │\n │ │\n └──────────────────────────────┘\n```\n\n## Operations\n\n```mdl\nop Create\n key: org.dxos.plugin.file.operation.create\n desc: |\n Validates a browser File object's MIME type, resolves the active\n BackendDescriptor, and composes File.fromBytes (which hashes/uploads the\n bytes via the Blob API and adds the resulting Blob to the database) to\n construct a File ECHO object. Does not add the File object itself to the\n space — callers do that separately.\n input:\n file: BrowserFile # browser File (globalThis.File)\n db: Database\n output: { object: File }\n errors:\n UnsupportedFileTypeError: MIME type is not image/*, video/*, or application/pdf\n FileTooLargeError: file exceeds the 4 MB inline limit (only possible when the\n resolved backend's storage is 'inline'; other backends scale beyond it)\n NoBackendError: no BackendDescriptor capability is registered\n```\n\n## Features\n\n```mdl\nfeat F-1: File upload\n\n req F-1.1: Accepted MIME types MUST be image/* (jpg, jpeg, png, gif, webp, svg),\n video/* (mp4, webm, mov), and application/pdf only.\n\n req F-1.2: Maximum upload size MUST be 4 MB when the resolved backend's storage\n is 'inline'. Other backends (e.g. edge, wnfs) are not subject to this cap.\n\n req F-1.3:\n when: user submits the Create Object form with a valid file\n then:\n - op:Create is invoked with the selected file and active database\n - the resulting File object is added to the space via SpaceOperation.AddObject\n - FileUploader capability returns metadata to the caller (name, type, and a\n renderable url resolved via Blob.url, if one is available)\n\n req F-1.4:\n when: file MIME type is not accepted\n then: UnsupportedFileTypeError returned; no ECHO write occurs\n\n req F-1.5:\n when: file size exceeds the limit and the resolved backend's storage is 'inline'\n then: FileTooLargeError returned; no ECHO write occurs\n```\n\n```mdl\nfeat F-2: Backend capability system\n\n req F-2.1: Any plugin may contribute a BackendDescriptor capability. Multiple\n descriptors may be registered simultaneously.\n\n req F-2.2: The inline BackendDescriptor MUST always be registered by FilePlugin\n itself, mapping to Blob's built-in 'inline' storage (bytes embedded on the\n Blob object; no separate BlobBackend registration needed).\n\n req F-2.3: The active backend is determined by Settings.backend. If the\n configured id is absent or unrecognised, the inline backend is used.\n\n req F-2.4: A BackendDescriptor's `storage` names the Blob storage used by\n File.fromBytes; the actual upload/read/getUrl implementation lives in a\n separate `BlobBackend` registered on the ECHO Hypergraph (via\n `client.graph.registerBlobBackend`), typically by the same plugin that\n contributes the descriptor (e.g. plugin-wnfs, or `@dxos/client` itself for\n 'edge'). FilePlugin's descriptor and the Hypergraph's BlobBackend registry\n are independent — a descriptor with no matching registered backend fails at\n upload time with a `backend-not-registered` error, not at settings-selection time.\n```\n\n```mdl\nfeat F-3: File preview\n\n req F-3.1: FileArticle MUST resolve a renderable URL via Blob.url before\n rendering FilePreview. For inline files this is always a data: URL\n (constructed synchronously from the stored bytes, no Blob.read needed). For\n external files with no registered getUrl, FileArticle falls back to\n Blob.read and constructs a blob: URL, revoked on unmount.\n\n req F-3.2: FilePreview MUST render the appropriate element for each MIME class:\n image/* → <img>, video/* → <video controls>, application/pdf → <iframe>,\n other → <a download>.\n\n req F-3.3: FileArticle surfaces are registered for article, section,\n and slide roles so files embed correctly in Markdown and Presenter layouts.\n```\n\n```mdl\nfeat F-4: Markdown integration\n\n req F-4.1: A Markdown extension contributed at MarkdownEvents.SetupExtensions\n MUST allow files to be embedded in Markdown documents as inline attachments,\n resolving each embedded File's Blob URL the same way as FileArticle (Blob.url,\n falling back to Blob.read + blob: URL).\n```\n\n```mdl\nfeat F-5: Settings\n\n req F-5.1: The Settings panel MUST list all registered BackendDescriptor\n capabilities with their id, display name, and optional description.\n\n req F-5.2: Selecting a backend MUST persist the choice to Settings.backend\n via the SettingsAtom capability.\n```\n\n## Acceptance\n\n```mdl\ntest T-1: Upload image inline\n given: only the inline BackendDescriptor is registered\n when: user uploads a 1 MB PNG via the Create Object form\n then:\n - op:Create returns a File whose data Ref resolves to a Blob with data._tag === 'inline'\n - File.type === 'image/png', File.size === byte count\n - File is added to the space\n```\n\n```mdl\ntest T-2: Reject oversized file\n given: inline backend selected, 4 MB limit\n when: user uploads a 5 MB JPEG\n then:\n - FileTooLargeError is returned\n - no File object is created\n - no ECHO write occurs\n```\n\n```mdl\ntest T-3: Reject unsupported MIME type\n given: inline backend registered\n when: user uploads a .zip file\n then:\n - UnsupportedFileTypeError is returned\n - no File object is created\n```\n\n```mdl\ntest T-4: Preview inline image\n given: a File whose data Ref resolves to a Blob with data._tag === 'inline' and type === 'image/png'\n when: FileArticle is rendered\n then:\n - Blob.url resolves a data: URL synchronously from the Blob's bytes (no Blob.read call)\n - FilePreview renders an <img> element with that URL\n```\n\n```mdl\ntest T-5: Preview PDF\n given: a File with type === 'application/pdf' and a Blob resolved to an HTTP or data URL\n when: FilePreview is rendered\n then: an <iframe> element is rendered with the file URL as src\n```\n\n```mdl\ntest T-6: Backend fallback to inline\n given: Settings.backend is 'wnfs' but no BackendDescriptor with storage 'wnfs' is registered\n when: op:Create is invoked\n then: the inline backend is used and the file is stored inline\n```\n\n```mdl\ntest T-7: External blob resolved via a registered BlobBackend's getUrl\n given: a File whose data Ref resolves to a Blob with data._tag === 'external' and a\n BlobBackend registered on the ECHO Hypergraph that resolves the Blob's URI scheme\n and implements getUrl\n when: FileArticle is rendered\n then:\n - Blob.url calls the registered backend's getUrl and resolves Some(url)\n - FilePreview receives the resolved renderable URL\n - Blob.read is never called\n```\n\n```mdl\ntest T-8: External blob without getUrl falls back to reading bytes\n given: a File whose data Ref resolves to an external Blob whose registered\n BlobBackend implements get but not getUrl\n when: FileArticle is rendered\n then:\n - Blob.url resolves None\n - Blob.read is called to fetch the bytes\n - a blob: object URL is created from the bytes and revoked on unmount\n```\n\n```mdl\ntest T-9: No backend error\n given: no BackendDescriptor capability is registered\n when: op:Create is invoked\n then: NoBackendError is returned\n```\n\n---\n\n## Appendix: Extension Definitions\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap\n literals?: UnionList\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self\n```\n\n```mdl\next test\n uri: org.dxos.mdl.test@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap\n state?: FieldMap\n slots?: FieldMap\n actions?: ActionMap\n emits?: EventMap\n layout?: CodeBlock\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: A named operation with typed inputs, outputs, and declared errors.\n fields:\n desc?: Prose\n input?: FieldMap\n output?: TypeExpr\n errors?: ErrorMap\n effects?: EffectList\n requires?: ServiceList\n note?: Prose\n```\n",
32
14
  mimeType: "application/x-mdl"
33
- } }), Plugin.make);
15
+ })), Plugin.make);
34
16
  //#endregion
35
17
  export { FilePlugin, FilePlugin as default };
36
18
 
@@ -1 +1 @@
1
- {"version":3,"file":"FilePlugin.mjs","names":[],"sources":["../../src/FilePlugin.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';\nimport { Blob } from '@dxos/echo';\nimport { ClientEvents } from '@dxos/plugin-client';\nimport { MarkdownEvents } from '@dxos/plugin-markdown';\n\nimport {\n CreateObject,\n EdgeBackend,\n FileUploader,\n InlineBackend,\n Markdown,\n OperationHandler,\n ReactSurface,\n Settings,\n SkillDefinition,\n} from '#capabilities';\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { File } from '#types';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../PLUGIN.mdl?raw';\n\nexport const FilePlugin = Plugin.define(meta).pipe(\n AppPlugin.addSkillDefinitionModule({ activate: SkillDefinition }),\n AppPlugin.addCreateObjectModule({ activate: CreateObject }),\n AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),\n AppPlugin.addSchemaModule({ schema: [File.File, Blob.Blob] }),\n AppPlugin.addSettingsModule({ activate: Settings }),\n AppPlugin.addSurfaceModule({ activate: ReactSurface }),\n AppPlugin.addTranslationsModule({ translations }),\n Plugin.addModule({\n id: 'inline-backend',\n activatesOn: AppActivationEvents.SetupSchema,\n activate: InlineBackend,\n }),\n Plugin.addModule({\n id: 'file-uploader',\n activatesOn: ClientEvents.ClientReady,\n activate: FileUploader,\n }),\n Plugin.addModule({\n id: 'edge-backend',\n activatesOn: ClientEvents.ClientReady,\n activate: EdgeBackend,\n }),\n Plugin.addModule({\n id: 'markdown',\n activatesOn: MarkdownEvents.SetupExtensions,\n activate: Markdown,\n }),\n AppPlugin.addPluginAssetModule({\n asset: { pluginId: meta.profile.key, path: 'PLUGIN.mdl', content: pluginSpec, mimeType: 'application/x-mdl' },\n }),\n Plugin.make,\n);\n\nexport default FilePlugin;\n"],"mappings":";;;;;;;;;;;AA4BA,IAAa,aAAa,OAAO,OAAO,IAAI,CAAC,CAAC,KAC5C,UAAU,yBAAyB,EAAE,UAAU,gBAAgB,CAAC,GAChE,UAAU,sBAAsB,EAAE,UAAU,aAAa,CAAC,GAC1D,UAAU,0BAA0B,EAAE,UAAU,iBAAiB,CAAC,GAClE,UAAU,gBAAgB,EAAE,QAAQ,CAAC,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,GAC5D,UAAU,kBAAkB,EAAE,UAAU,SAAS,CAAC,GAClD,UAAU,iBAAiB,EAAE,UAAU,aAAa,CAAC,GACrD,UAAU,sBAAsB,EAAE,aAAa,CAAC,GAChD,OAAO,UAAU;CACf,IAAI;CACJ,aAAa,oBAAoB;CACjC,UAAU;AACZ,CAAC,GACD,OAAO,UAAU;CACf,IAAI;CACJ,aAAa,aAAa;CAC1B,UAAU;AACZ,CAAC,GACD,OAAO,UAAU;CACf,IAAI;CACJ,aAAa,aAAa;CAC1B,UAAU;AACZ,CAAC,GACD,OAAO,UAAU;CACf,IAAI;CACJ,aAAa,eAAe;CAC5B,UAAU;AACZ,CAAC,GACD,UAAU,qBAAqB,EAC7B,OAAO;CAAE,UAAU,KAAK,QAAQ;CAAK,MAAM;CAAc,SAAS;CAAY,UAAU;AAAoB,EAC9G,CAAC,GACD,OAAO,IACT"}
1
+ {"version":3,"file":"FilePlugin.mjs","names":[],"sources":["../../src/FilePlugin.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport { Blob } from '@dxos/echo';\nimport { File } from '@dxos/types';\n\nimport {\n CreateObject,\n EdgeBackend,\n FileUploader,\n InlineBackend,\n Markdown,\n OperationHandler,\n ReactSurface,\n Settings,\n SkillDefinition,\n} from '#capabilities';\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../PLUGIN.mdl?raw';\n\nexport const FilePlugin = Plugin.define(meta).pipe(\n Plugin.addModule(SkillDefinition),\n Plugin.addModule(CreateObject),\n Plugin.addModule(OperationHandler),\n Plugin.addModule(AppCapability.schema([File.File, Blob.Blob])),\n Plugin.addModule(Settings),\n Plugin.addModule(ReactSurface),\n Plugin.addModule(AppCapability.translations(translations)),\n Plugin.addModule(InlineBackend),\n Plugin.addModule(FileUploader),\n Plugin.addModule(EdgeBackend),\n Plugin.addModule(Markdown),\n Plugin.addModule(\n AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n }),\n ),\n Plugin.make,\n);\n\nexport default FilePlugin;\n"],"mappings":";;;;;;;;;AA0BA,IAAa,aAAa,OAAO,OAAO,IAAI,CAAC,CAAC,KAC5C,OAAO,UAAU,eAAe,GAChC,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,gBAAgB,GACjC,OAAO,UAAU,cAAc,OAAO,CAAC,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,GAC7D,OAAO,UAAU,QAAQ,GACzB,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,cAAc,aAAa,YAAY,CAAC,GACzD,OAAO,UAAU,aAAa,GAC9B,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,WAAW,GAC5B,OAAO,UAAU,QAAQ,GACzB,OAAO,UACL,cAAc,YAAY;CACxB,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC,CACH,GACA,OAAO,IACT"}
@@ -1,11 +1,11 @@
1
1
  import { meta } from "#meta";
2
- import { Plugin } from "@dxos/app-framework";
3
2
  import { Blob } from "@dxos/echo";
4
- import { AppPlugin } from "@dxos/app-toolkit";
5
- import { CreateObject, OperationHandler } from "#capabilities";
6
- import { File } from "#types";
3
+ import { File } from "@dxos/types";
4
+ import * as Plugin from "@dxos/app-framework/Plugin";
5
+ import * as AppCapability from "@dxos/app-toolkit/AppCapability";
6
+ import { CreateObject, EdgeBackend, InlineBackend, OperationHandler, SkillDefinition } from "#capabilities";
7
7
  //#region src/FilePlugin.node.ts
8
- var FilePlugin = Plugin.define(meta).pipe(AppPlugin.addCreateObjectModule({ activate: CreateObject }), AppPlugin.addOperationHandlerModule({ activate: OperationHandler }), AppPlugin.addSchemaModule({ schema: [File.File, Blob.Blob] }), Plugin.make);
8
+ var FilePlugin = Plugin.define(meta).pipe(Plugin.addModule(CreateObject), Plugin.addModule(EdgeBackend), Plugin.addModule(InlineBackend), Plugin.addModule(OperationHandler), Plugin.addModule(SkillDefinition), Plugin.addModule(AppCapability.schema([File.File, Blob.Blob])), Plugin.make);
9
9
  //#endregion
10
10
  export { FilePlugin, FilePlugin as default };
11
11
 
@@ -1 +1 @@
1
- {"version":3,"file":"FilePlugin.node.mjs","names":[],"sources":["../../src/FilePlugin.node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\nimport { Blob } from '@dxos/echo';\n\nimport { CreateObject, OperationHandler } from '#capabilities';\nimport { meta } from '#meta';\nimport { File } from '#types';\n\nexport const FilePlugin = Plugin.define(meta).pipe(\n AppPlugin.addCreateObjectModule({ activate: CreateObject }),\n AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),\n AppPlugin.addSchemaModule({ schema: [File.File, Blob.Blob] }),\n Plugin.make,\n);\n\nexport default FilePlugin;\n"],"mappings":";;;;;;;AAYA,IAAa,aAAa,OAAO,OAAO,IAAI,CAAC,CAAC,KAC5C,UAAU,sBAAsB,EAAE,UAAU,aAAa,CAAC,GAC1D,UAAU,0BAA0B,EAAE,UAAU,iBAAiB,CAAC,GAClE,UAAU,gBAAgB,EAAE,QAAQ,CAAC,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,GAC5D,OAAO,IACT"}
1
+ {"version":3,"file":"FilePlugin.node.mjs","names":[],"sources":["../../src/FilePlugin.node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport { Blob } from '@dxos/echo';\nimport { File } from '@dxos/types';\n\nimport { CreateObject, EdgeBackend, InlineBackend, OperationHandler, SkillDefinition } from '#capabilities';\nimport { meta } from '#meta';\n\nexport const FilePlugin = Plugin.define(meta).pipe(\n Plugin.addModule(CreateObject),\n Plugin.addModule(EdgeBackend),\n Plugin.addModule(InlineBackend),\n Plugin.addModule(OperationHandler),\n Plugin.addModule(SkillDefinition),\n Plugin.addModule(AppCapability.schema([File.File, Blob.Blob])),\n Plugin.make,\n);\n\nexport default FilePlugin;\n"],"mappings":";;;;;;;AAYA,IAAa,aAAa,OAAO,OAAO,IAAI,CAAC,CAAC,KAC5C,OAAO,UAAU,YAAY,GAC7B,OAAO,UAAU,WAAW,GAC5B,OAAO,UAAU,aAAa,GAC9B,OAAO,UAAU,gBAAgB,GACjC,OAAO,UAAU,eAAe,GAChC,OAAO,UAAU,cAAc,OAAO,CAAC,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,GAC7D,OAAO,IACT"}
@@ -0,0 +1,16 @@
1
+ import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
+ import * as Schema from "effect/Schema";
3
+ //#region src/types/Settings.ts
4
+ var Settings_exports = /* @__PURE__ */ __exportAll({
5
+ DEFAULT_BACKEND_STORAGE: () => DEFAULT_BACKEND_STORAGE,
6
+ Settings: () => Settings
7
+ });
8
+ var DEFAULT_BACKEND_STORAGE = "inline";
9
+ var Settings = Schema.mutable(Schema.Struct({ backend: Schema.optional(Schema.String.annotations({
10
+ title: "File storage backend",
11
+ description: "Where uploaded files are stored. Defaults to inline (bytes saved on the ECHO object). Install additional plugins (e.g. WNFS) to add external backends."
12
+ })) }));
13
+ //#endregion
14
+ export { DEFAULT_BACKEND_STORAGE, Settings, Settings_exports as t };
15
+
16
+ //# sourceMappingURL=Settings.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Settings.mjs","names":[],"sources":["../../src/types/Settings.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nexport const DEFAULT_BACKEND_STORAGE = 'inline';\n\nexport const Settings = Schema.mutable(\n Schema.Struct({\n backend: Schema.optional(\n Schema.String.annotations({\n title: 'File storage backend',\n description:\n 'Where uploaded files are stored. Defaults to inline (bytes saved on the ECHO object). Install additional plugins (e.g. WNFS) to add external backends.',\n }),\n ),\n }),\n);\n\nexport interface Settings extends Schema.Schema.Type<typeof Settings> {}\n"],"mappings":";;;;;;;AAQA,IAAa,0BAA0B;AAEvC,IAAa,WAAW,OAAO,QAC7B,OAAO,OAAO,EACZ,SAAS,OAAO,SACd,OAAO,OAAO,YAAY;CACxB,OAAO;CACP,aACE;AACJ,CAAC,CACH,EACF,CAAC,CACH"}
@@ -1,8 +1,24 @@
1
- import { Capability } from "@dxos/app-framework";
1
+ import { Backend } from "../FileCapabilities.mjs";
2
+ import { Start } from "../FileEvents.mjs";
3
+ import * as Capability from "@dxos/app-framework/Capability";
4
+ import * as AppCapability from "@dxos/app-toolkit/AppCapability";
5
+ import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
6
+ import * as ClientCapabilities from "@dxos/plugin-client/ClientCapabilities";
7
+ import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
2
8
  //#region src/capabilities/node.ts
3
- var CreateObject = Capability.lazy("CreateObject", () => import("../chunk-create-object.mjs"));
4
- var OperationHandler = Capability.lazy("OperationHandler", () => import("../chunk-operation-handler.mjs"));
9
+ var CreateObject = SpaceCapability.createObject(() => import("../chunk-create-object.mjs"));
10
+ var EdgeBackend = Capability.lazyModule("EdgeBackend", {
11
+ requires: [ClientCapabilities.Client],
12
+ provides: [Backend],
13
+ activatesOn: Start
14
+ }, () => import("../chunk-edge-backend.mjs"));
15
+ var InlineBackend = Capability.lazyModule("InlineBackend", {
16
+ provides: [Backend],
17
+ activatesOn: Start
18
+ }, () => import("../chunk-inline-backend.mjs"));
19
+ var OperationHandler = AppCapability.operationHandler(() => import("../chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
20
+ var SkillDefinition = AppCapability.skillDefinition(() => import("../chunk-skill-definition.mjs"));
5
21
  //#endregion
6
- export { CreateObject, OperationHandler };
22
+ export { CreateObject, EdgeBackend, InlineBackend, OperationHandler, SkillDefinition };
7
23
 
8
24
  //# sourceMappingURL=node.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.mjs","names":[],"sources":["../../../src/capabilities/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Capability } from '@dxos/app-framework';\nimport { OperationHandlerSet } from '@dxos/compute';\n\n// The capabilities `FilePlugin.node` activates, and only those. `Capability.lazy` defers the\n// import at runtime but a bundler still walks it, so listing the React surfaces here would pull\n// the plugin's components into every node and bun build.\n\nexport const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));\nexport const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(\n 'OperationHandler',\n () => import('./operation-handler'),\n);\n"],"mappings":";;AAWA,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,6BAAkB;AAC3F,IAAa,mBAAmB,WAAW,KACzC,0BACM,OAAO,iCACf"}
1
+ {"version":3,"file":"node.mjs","names":[],"sources":["../../../src/capabilities/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ClientCapabilities from '@dxos/plugin-client/ClientCapabilities';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport * as FileCapabilities from '../types/FileCapabilities';\nimport * as FileEvents from '../types/FileEvents';\n\n// The capabilities `FilePlugin.node` activates, and only those. A lazy module defers its import at\n// runtime but a bundler still walks it, so listing the React surfaces here would pull the plugin's\n// components into every node and bun build.\n\nexport const CreateObject = SpaceCapability.createObject(() => import('./create-object'));\nexport const EdgeBackend = Capability.lazyModule(\n 'EdgeBackend',\n {\n requires: [ClientCapabilities.Client],\n provides: [FileCapabilities.Backend],\n activatesOn: FileEvents.Start,\n },\n () => import('./edge-backend'),\n);\nexport const InlineBackend = Capability.lazyModule(\n 'InlineBackend',\n { provides: [FileCapabilities.Backend], activatesOn: FileEvents.Start },\n () => import('./inline-backend'),\n);\nexport const OperationHandler = AppCapability.operationHandler(() => import('./operation-handler'), {\n activatesOn: ActivationEvents.Idle,\n});\nexport const SkillDefinition = AppCapability.skillDefinition(() => import('./skill-definition'));\n"],"mappings":";;;;;;;;AAiBA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,6BAAkB;AACxF,IAAa,cAAc,WAAW,WACpC,eACA;CACE,UAAU,CAAC,mBAAmB,MAAM;CACpC,UAAU,CAAC,OAAwB;CACnC,aAAa;AACf,SACM,OAAO,4BACf;AACA,IAAa,gBAAgB,WAAW,WACtC,iBACA;CAAE,UAAU,CAAC,OAAwB;CAAG,aAAa;AAAiB,SAChE,OAAO,8BACf;AACA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,mCAAwB,EAClG,aAAa,iBAAiB,KAChC,CAAC;AACD,IAAa,kBAAkB,cAAc,sBAAsB,OAAO,gCAAqB"}
@@ -1,14 +1,46 @@
1
- import { Capability } from "@dxos/app-framework";
1
+ import { Backend, SettingsAtom } from "./FileCapabilities.mjs";
2
+ import { Start } from "./FileEvents.mjs";
3
+ import * as Capability from "@dxos/app-framework/Capability";
4
+ import * as AppCapability from "@dxos/app-toolkit/AppCapability";
5
+ import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
6
+ import * as Capabilities from "@dxos/app-framework/Capabilities";
7
+ import * as AppCapabilities from "@dxos/app-toolkit/AppCapabilities";
8
+ import * as ClientCapabilities from "@dxos/plugin-client/ClientCapabilities";
9
+ import * as MarkdownCapabilities from "@dxos/plugin-markdown/MarkdownCapabilities";
10
+ import * as MarkdownEvents from "@dxos/plugin-markdown/MarkdownEvents";
11
+ import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
2
12
  //#region src/capabilities/index.ts
3
- var SkillDefinition = Capability.lazy("SkillDefinition", () => import("./chunk-skill-definition.mjs"));
4
- var CreateObject = Capability.lazy("CreateObject", () => import("./chunk-create-object.mjs"));
5
- var EdgeBackend = Capability.lazy("EdgeBackend", () => import("./chunk-edge-backend.mjs"));
6
- var FileUploader = Capability.lazy("FileUploader", () => import("./chunk-file-uploader.mjs"));
7
- var InlineBackend = Capability.lazy("InlineBackend", () => import("./chunk-inline-backend.mjs"));
8
- var Markdown = Capability.lazy("MarkdownExtension", () => import("./chunk-markdown-extension.mjs"));
9
- var OperationHandler = Capability.lazy("OperationHandler", () => import("./chunk-operation-handler.mjs"));
10
- var ReactSurface = Capability.lazy("ReactSurface", () => import("./chunk-react-surface.mjs"));
11
- var Settings = Capability.lazy("Settings", () => import("./chunk-settings.mjs"));
13
+ var SkillDefinition = AppCapability.skillDefinition(() => import("./chunk-skill-definition.mjs"));
14
+ var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"));
15
+ var EdgeBackend = Capability.lazyModule("EdgeBackend", {
16
+ requires: [ClientCapabilities.Client],
17
+ provides: [Backend],
18
+ activatesOn: Start
19
+ }, () => import("./chunk-edge-backend.mjs"));
20
+ var FileUploader = Capability.lazyModule("FileUploader", {
21
+ requires: [Capabilities.OperationInvoker],
22
+ provides: [AppCapabilities.FileUploader],
23
+ activatesOn: Start
24
+ }, () => import("./chunk-file-uploader.mjs"));
25
+ var InlineBackend = Capability.lazyModule("InlineBackend", {
26
+ provides: [Backend],
27
+ activatesOn: Start
28
+ }, () => import("./chunk-inline-backend.mjs"));
29
+ var Markdown = Capability.lazyModule("MarkdownExtension", {
30
+ provides: [MarkdownCapabilities.ExtensionProvider],
31
+ activatesOn: MarkdownEvents.Start
32
+ }, () => import("./chunk-markdown-extension.mjs"));
33
+ var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
34
+ var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: [
35
+ "org.dxos.role.article",
36
+ "org.dxos.role.formInput",
37
+ "org.dxos.role.section",
38
+ "org.dxos.role.slide"
39
+ ] });
40
+ var Settings = AppCapability.settings(() => import("./chunk-settings.mjs"), {
41
+ activatesOn: ActivationEvents.Idle,
42
+ provides: [SettingsAtom]
43
+ });
12
44
  //#endregion
13
45
  export { CreateObject, EdgeBackend, FileUploader, InlineBackend, Markdown, OperationHandler, ReactSurface, Settings, SkillDefinition };
14
46
 
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Capability } from '@dxos/app-framework';\nimport { OperationHandlerSet } from '@dxos/compute';\n\nexport const SkillDefinition = Capability.lazy('SkillDefinition', () => import('./skill-definition'));\nexport const CreateObject = Capability.lazy('CreateObject', () => import('./create-object'));\nexport const EdgeBackend = Capability.lazy('EdgeBackend', () => import('./edge-backend'));\nexport const FileUploader = Capability.lazy('FileUploader', () => import('./file-uploader'));\nexport const InlineBackend = Capability.lazy('InlineBackend', () => import('./inline-backend'));\nexport const Markdown = Capability.lazy('MarkdownExtension', () => import('./markdown-extension'));\nexport const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(\n 'OperationHandler',\n () => import('./operation-handler'),\n);\nexport const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));\nexport const Settings = Capability.lazy('Settings', () => import('./settings'));\n"],"mappings":";;AAOA,IAAa,kBAAkB,WAAW,KAAK,yBAAyB,OAAO,+BAAqB;AACpG,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,4BAAkB;AAC3F,IAAa,cAAc,WAAW,KAAK,qBAAqB,OAAO,2BAAiB;AACxF,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,4BAAkB;AAC3F,IAAa,gBAAgB,WAAW,KAAK,uBAAuB,OAAO,6BAAmB;AAC9F,IAAa,WAAW,WAAW,KAAK,2BAA2B,OAAO,iCAAuB;AACjG,IAAa,mBAAmB,WAAW,KACzC,0BACM,OAAO,gCACf;AACA,IAAa,eAAe,WAAW,KAAK,sBAAsB,OAAO,4BAAkB;AAC3F,IAAa,WAAW,WAAW,KAAK,kBAAkB,OAAO,uBAAa"}
1
+ {"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ClientCapabilities from '@dxos/plugin-client/ClientCapabilities';\nimport * as MarkdownCapabilities from '@dxos/plugin-markdown/MarkdownCapabilities';\nimport * as MarkdownEvents from '@dxos/plugin-markdown/MarkdownEvents';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport * as FileCapabilities from '../types/FileCapabilities';\nimport * as FileEvents from '../types/FileEvents';\n\nexport const SkillDefinition = AppCapability.skillDefinition(() => import('./skill-definition'));\nexport const CreateObject = SpaceCapability.createObject(() => import('./create-object'));\nexport const EdgeBackend = Capability.lazyModule(\n 'EdgeBackend',\n {\n requires: [ClientCapabilities.Client],\n provides: [FileCapabilities.Backend],\n activatesOn: FileEvents.Start,\n },\n () => import('./edge-backend'),\n);\nexport const FileUploader = Capability.lazyModule(\n 'FileUploader',\n {\n requires: [Capabilities.OperationInvoker],\n provides: [AppCapabilities.FileUploader],\n activatesOn: FileEvents.Start,\n },\n () => import('./file-uploader'),\n);\nexport const InlineBackend = Capability.lazyModule(\n 'InlineBackend',\n { provides: [FileCapabilities.Backend], activatesOn: FileEvents.Start },\n () => import('./inline-backend'),\n);\nexport const Markdown = Capability.lazyModule(\n 'MarkdownExtension',\n { provides: [MarkdownCapabilities.ExtensionProvider], activatesOn: MarkdownEvents.Start },\n () => import('./markdown-extension'),\n);\nexport const OperationHandler = AppCapability.operationHandler(() => import('./operation-handler'), {\n activatesOn: ActivationEvents.Idle,\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface'), {\n roles: ['org.dxos.role.article', 'org.dxos.role.formInput', 'org.dxos.role.section', 'org.dxos.role.slide'],\n});\nexport const Settings = AppCapability.settings(() => import('./settings'), {\n activatesOn: ActivationEvents.Idle,\n provides: [FileCapabilities.SettingsAtom],\n});\n"],"mappings":";;;;;;;;;;;;AAiBA,IAAa,kBAAkB,cAAc,sBAAsB,OAAO,+BAAqB;AAC/F,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,4BAAkB;AACxF,IAAa,cAAc,WAAW,WACpC,eACA;CACE,UAAU,CAAC,mBAAmB,MAAM;CACpC,UAAU,CAAC,OAAwB;CACnC,aAAa;AACf,SACM,OAAO,2BACf;AACA,IAAa,eAAe,WAAW,WACrC,gBACA;CACE,UAAU,CAAC,aAAa,gBAAgB;CACxC,UAAU,CAAC,gBAAgB,YAAY;CACvC,aAAa;AACf,SACM,OAAO,4BACf;AACA,IAAa,gBAAgB,WAAW,WACtC,iBACA;CAAE,UAAU,CAAC,OAAwB;CAAG,aAAa;AAAiB,SAChE,OAAO,6BACf;AACA,IAAa,WAAW,WAAW,WACjC,qBACA;CAAE,UAAU,CAAC,qBAAqB,iBAAiB;CAAG,aAAa,eAAe;AAAM,SAClF,OAAO,iCACf;AACA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAAwB,EAClG,aAAa,iBAAiB,KAChC,CAAC;AACD,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAoB,EACjF,OAAO;CAAC;CAAyB;CAA2B;CAAyB;AAAqB,EAC5G,CAAC;AACD,IAAa,WAAW,cAAc,eAAe,OAAO,yBAAe;CACzE,aAAa,iBAAiB;CAC9B,UAAU,CAAC,YAA6B;AAC1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-FileArticle.mjs","names":[],"sources":["../../src/containers/FileArticle/FileArticle.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport React, { useEffect, useState } from 'react';\n\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Blob, Database, Obj } from '@dxos/echo';\nimport { EffectEx } from '@dxos/effect';\nimport { Panel } from '@dxos/react-ui';\n\nimport { FilePreview } from '#components';\nimport { File } from '#types';\n\nexport type FileArticleProps = AppSurface.ObjectArticleProps<File.File>;\n\nexport const FileArticle = ({ role, subject: file }: FileArticleProps) => {\n const [rendered, setRendered] = useState<{ url: string; type: string } | undefined>(undefined);\n\n useEffect(() => {\n setRendered(undefined);\n\n const db = Obj.getDatabase(file);\n if (!db) {\n return;\n }\n\n let cancelled = false;\n let createdBlobUrl: string | undefined;\n\n const program = Effect.gen(function* () {\n const blob = yield* Database.load(file.data);\n const type = blob.type ?? 'application/octet-stream';\n const urlOption = yield* Blob.url(blob);\n if (Option.isSome(urlOption)) {\n return { url: urlOption.value, type };\n }\n const bytes = yield* Blob.read(blob);\n // `Uint8Array` is generic over `ArrayBufferLike` (incl. `SharedArrayBuffer`) while DOM's\n // `BlobPart` only covers `ArrayBuffer`-backed views — a gap between the DOM lib types and\n // the TS standard lib, not fixable by typing `bytes` differently.\n const url = URL.createObjectURL(new globalThis.Blob([bytes as BlobPart], { type }));\n return { url, type };\n }).pipe(\n Effect.provide(Database.layer(db)),\n Effect.catchAll(() => Effect.succeed(undefined)),\n );\n\n void EffectEx.runPromise(program).then((result) => {\n if (cancelled) {\n if (result?.url.startsWith('blob:')) {\n URL.revokeObjectURL(result.url);\n }\n return;\n }\n if (result?.url.startsWith('blob:')) {\n createdBlobUrl = result.url;\n }\n setRendered(result);\n });\n\n return () => {\n cancelled = true;\n if (createdBlobUrl) {\n URL.revokeObjectURL(createdBlobUrl);\n }\n };\n // Keyed on `file.id` rather than `file`/`file.data` directly: ECHO's reactive proxy returns a\n // fresh `Ref` wrapper for `.data` on every access, so including it (or the proxy object itself)\n // here would rerun this effect on every render — clearing the render state and re-resolving it\n // each time, which flickers the image while the object settles.\n }, [file.id]);\n\n if (!rendered) {\n return null;\n }\n\n return (\n <Panel.Root role={role} classNames='dx-document'>\n <Panel.Content asChild>\n <FilePreview type={rendered.type} url={rendered.url} />\n </Panel.Content>\n </Panel.Root>\n );\n};\n\nexport default FileArticle;\n\nFileArticle.displayName = 'FileArticle';\n"],"mappings":";;;;;;;;;AAkBA,IAAa,eAAe,EAAE,MAAM,SAAS,WAA6B;CACxE,MAAM,CAAC,UAAU,eAAe,SAAoD,KAAA,CAAS;CAE7F,gBAAgB;EACd,YAAY,KAAA,CAAS;EAErB,MAAM,KAAK,IAAI,YAAY,IAAI;EAC/B,IAAI,CAAC,IACH;EAGF,IAAI,YAAY;EAChB,IAAI;EAEJ,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,IAAI;GAC3C,MAAM,OAAO,KAAK,QAAQ;GAC1B,MAAM,YAAY,OAAO,KAAK,IAAI,IAAI;GACtC,IAAI,OAAO,OAAO,SAAS,GACzB,OAAO;IAAE,KAAK,UAAU;IAAO;GAAK;GAEtC,MAAM,QAAQ,OAAO,KAAK,KAAK,IAAI;GAKnC,OAAO;IAAE,KADG,IAAI,gBAAgB,IAAI,WAAW,KAAK,CAAC,KAAiB,GAAG,EAAE,KAAK,CAAC,CACxE;IAAK;GAAK;EACrB,CAAC,CAAC,CAAC,KACD,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,GACjC,OAAO,eAAe,OAAO,QAAQ,KAAA,CAAS,CAAC,CACjD;EAEA,SAAc,WAAW,OAAO,CAAC,CAAC,MAAM,WAAW;GACjD,IAAI,WAAW;IACb,IAAI,QAAQ,IAAI,WAAW,OAAO,GAChC,IAAI,gBAAgB,OAAO,GAAG;IAEhC;GACF;GACA,IAAI,QAAQ,IAAI,WAAW,OAAO,GAChC,iBAAiB,OAAO;GAE1B,YAAY,MAAM;EACpB,CAAC;EAED,aAAa;GACX,YAAY;GACZ,IAAI,gBACF,IAAI,gBAAgB,cAAc;EAEtC;CAKF,GAAG,CAAC,KAAK,EAAE,CAAC;CAEZ,IAAI,CAAC,UACH,OAAO;CAGT,OACE,oBAAC,MAAM,MAAP;EAAkB;EAAM,YAAW;YACjC,oBAAC,MAAM,SAAP;GAAe,SAAA;aACb,oBAAC,aAAD;IAAa,MAAM,SAAS;IAAM,KAAK,SAAS;GAAM,CAAA;EACzC,CAAA;CACL,CAAA;AAEhB;AAIA,YAAY,cAAc"}
1
+ {"version":3,"file":"chunk-FileArticle.mjs","names":[],"sources":["../../src/containers/FileArticle/FileArticle.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport React, { useEffect, useState } from 'react';\n\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Blob, Database, Obj } from '@dxos/echo';\nimport { EffectEx } from '@dxos/effect';\nimport { Panel } from '@dxos/react-ui';\nimport { File } from '@dxos/types';\n\nimport { FilePreview } from '#components';\n\nexport type FileArticleProps = AppSurface.ObjectArticleProps<File.File>;\n\nexport const FileArticle = ({ role, subject: file }: FileArticleProps) => {\n const [rendered, setRendered] = useState<{ url: string; type: string } | undefined>(undefined);\n\n useEffect(() => {\n setRendered(undefined);\n\n const db = Obj.getDatabase(file);\n if (!db) {\n return;\n }\n\n let cancelled = false;\n let createdBlobUrl: string | undefined;\n\n const program = Effect.gen(function* () {\n const blob = yield* Database.load(file.data);\n const type = blob.type ?? 'application/octet-stream';\n const urlOption = yield* Blob.url(blob);\n if (Option.isSome(urlOption)) {\n return { url: urlOption.value, type };\n }\n const bytes = yield* Blob.read(blob);\n // `Uint8Array` is generic over `ArrayBufferLike` (incl. `SharedArrayBuffer`) while DOM's\n // `BlobPart` only covers `ArrayBuffer`-backed views — a gap between the DOM lib types and\n // the TS standard lib, not fixable by typing `bytes` differently.\n const url = URL.createObjectURL(new globalThis.Blob([bytes as BlobPart], { type }));\n return { url, type };\n }).pipe(\n Effect.provide(Database.layer(db)),\n Effect.catchAll(() => Effect.succeed(undefined)),\n );\n\n void EffectEx.runPromise(program).then((result) => {\n if (cancelled) {\n if (result?.url.startsWith('blob:')) {\n URL.revokeObjectURL(result.url);\n }\n return;\n }\n if (result?.url.startsWith('blob:')) {\n createdBlobUrl = result.url;\n }\n setRendered(result);\n });\n\n return () => {\n cancelled = true;\n if (createdBlobUrl) {\n URL.revokeObjectURL(createdBlobUrl);\n }\n };\n // Keyed on `file.id` rather than `file`/`file.data` directly: ECHO's reactive proxy returns a\n // fresh `Ref` wrapper for `.data` on every access, so including it (or the proxy object itself)\n // here would rerun this effect on every render — clearing the render state and re-resolving it\n // each time, which flickers the image while the object settles.\n }, [file.id]);\n\n if (!rendered) {\n return null;\n }\n\n return (\n <Panel.Root role={role} classNames='dx-document'>\n <Panel.Content asChild>\n <FilePreview type={rendered.type} url={rendered.url} />\n </Panel.Content>\n </Panel.Root>\n );\n};\n\nexport default FileArticle;\n\nFileArticle.displayName = 'FileArticle';\n"],"mappings":";;;;;;;;;AAkBA,IAAa,eAAe,EAAE,MAAM,SAAS,WAA6B;CACxE,MAAM,CAAC,UAAU,eAAe,SAAoD,KAAA,CAAS;CAE7F,gBAAgB;EACd,YAAY,KAAA,CAAS;EAErB,MAAM,KAAK,IAAI,YAAY,IAAI;EAC/B,IAAI,CAAC,IACH;EAGF,IAAI,YAAY;EAChB,IAAI;EAEJ,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,OAAO,OAAO,SAAS,KAAK,KAAK,IAAI;GAC3C,MAAM,OAAO,KAAK,QAAQ;GAC1B,MAAM,YAAY,OAAO,KAAK,IAAI,IAAI;GACtC,IAAI,OAAO,OAAO,SAAS,GACzB,OAAO;IAAE,KAAK,UAAU;IAAO;GAAK;GAEtC,MAAM,QAAQ,OAAO,KAAK,KAAK,IAAI;GAKnC,OAAO;IAAE,KADG,IAAI,gBAAgB,IAAI,WAAW,KAAK,CAAC,KAAiB,GAAG,EAAE,KAAK,CAAC,CACxE;IAAK;GAAK;EACrB,CAAC,CAAC,CAAC,KACD,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,GACjC,OAAO,eAAe,OAAO,QAAQ,KAAA,CAAS,CAAC,CACjD;EAEA,SAAc,WAAW,OAAO,CAAC,CAAC,MAAM,WAAW;GACjD,IAAI,WAAW;IACb,IAAI,QAAQ,IAAI,WAAW,OAAO,GAChC,IAAI,gBAAgB,OAAO,GAAG;IAEhC;GACF;GACA,IAAI,QAAQ,IAAI,WAAW,OAAO,GAChC,iBAAiB,OAAO;GAE1B,YAAY,MAAM;EACpB,CAAC;EAED,aAAa;GACX,YAAY;GACZ,IAAI,gBACF,IAAI,gBAAgB,cAAc;EAEtC;CAKF,GAAG,CAAC,KAAK,EAAE,CAAC;CAEZ,IAAI,CAAC,UACH,OAAO;CAGT,OACE,oBAAC,MAAM,MAAP;EAAkB;EAAM,YAAW;YACjC,oBAAC,MAAM,SAAP;GAAe,SAAA;aACb,oBAAC,aAAD;IAAa,MAAM,SAAS;IAAM,KAAK,SAAS;GAAM,CAAA;EACzC,CAAA;CACL,CAAA;AAEhB;AAIA,YAAY,cAAc"}
@@ -1,16 +1,19 @@
1
- import { Operation } from "@dxos/compute";
2
- import { Capability } from "@dxos/app-framework";
1
+ import { FileAction } from "./FileCapabilities.mjs";
2
+ import { Create } from "./FileOperation.mjs";
3
+ import * as Capability from "@dxos/app-framework/Capability";
4
+ import * as Operation from "@dxos/compute/Operation";
3
5
  import { Type } from "@dxos/echo";
4
- import { File, FileAction, FileOperation } from "#types";
6
+ import { File } from "@dxos/types";
5
7
  import * as Effect from "effect/Effect";
6
- import { SpaceCapabilities, SpaceOperation } from "@dxos/plugin-space";
8
+ import { SpaceOperation } from "@dxos/plugin-space";
9
+ import * as SpaceCapabilities from "@dxos/plugin-space/SpaceCapabilities";
7
10
  //#region src/capabilities/create-object.ts
8
11
  var create_object_default = Capability.makeModule(Effect.fnUntraced(function* () {
9
- return Capability.contributes(SpaceCapabilities.CreateObjectEntry, {
12
+ return Capability.contribute(SpaceCapabilities.CreateObjectEntry, {
10
13
  id: Type.getTypename(File.File),
11
14
  inputSchema: FileAction.CreateFileSchema,
12
15
  createObject: (props, options) => Effect.gen(function* () {
13
- const { object } = yield* Operation.invoke(FileOperation.Create, {
16
+ const { object } = yield* Operation.invoke(Create, {
14
17
  ...props,
15
18
  db: options.db
16
19
  });
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-create-object.mjs","names":[],"sources":["../../src/capabilities/create-object.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capability } from '@dxos/app-framework';\nimport { Operation } from '@dxos/compute';\nimport { Type } from '@dxos/echo';\nimport { SpaceCapabilities, SpaceOperation } from '@dxos/plugin-space';\n\nimport { File, FileAction, FileOperation } from '#types';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contributes(SpaceCapabilities.CreateObjectEntry, {\n id: Type.getTypename(File.File),\n inputSchema: FileAction.CreateFileSchema,\n createObject: (props, options) =>\n Effect.gen(function* () {\n const { object } = yield* Operation.invoke(FileOperation.Create, { ...props, db: options.db });\n return yield* Operation.invoke(SpaceOperation.AddObject, {\n object,\n target: options.target,\n targetNodeId: options.targetNodeId,\n });\n }),\n });\n }),\n);\n"],"mappings":";;;;;;;AAaA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,YAAY,kBAAkB,mBAAmB;EACjE,IAAI,KAAK,YAAY,KAAK,IAAI;EAC9B,aAAa,WAAW;EACxB,eAAe,OAAO,YACpB,OAAO,IAAI,aAAa;GACtB,MAAM,EAAE,WAAW,OAAO,UAAU,OAAO,cAAc,QAAQ;IAAE,GAAG;IAAO,IAAI,QAAQ;GAAG,CAAC;GAC7F,OAAO,OAAO,UAAU,OAAO,eAAe,WAAW;IACvD;IACA,QAAQ,QAAQ;IAChB,cAAc,QAAQ;GACxB,CAAC;EACH,CAAC;CACL,CAAC;AACH,CAAC,CACH"}
1
+ {"version":3,"file":"chunk-create-object.mjs","names":[],"sources":["../../src/capabilities/create-object.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Type } from '@dxos/echo';\nimport { SpaceOperation } from '@dxos/plugin-space';\nimport * as SpaceCapabilities from '@dxos/plugin-space/SpaceCapabilities';\nimport { File } from '@dxos/types';\n\nimport * as FileCapabilities from '../types/FileCapabilities';\nimport * as FileOperation from '../types/FileOperation';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(SpaceCapabilities.CreateObjectEntry, {\n id: Type.getTypename(File.File),\n inputSchema: FileCapabilities.FileAction.CreateFileSchema,\n createObject: (props, options) =>\n Effect.gen(function* () {\n const { object } = yield* Operation.invoke(FileOperation.Create, { ...props, db: options.db });\n return yield* Operation.invoke(SpaceOperation.AddObject, {\n object,\n target: options.target,\n targetNodeId: options.targetNodeId,\n });\n }),\n });\n }),\n);\n"],"mappings":";;;;;;;;;;AAgBA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,kBAAkB,mBAAmB;EAChE,IAAI,KAAK,YAAY,KAAK,IAAI;EAC9B,aAAA,WAAyC;EACzC,eAAe,OAAO,YACpB,OAAO,IAAI,aAAa;GACtB,MAAM,EAAE,WAAW,OAAO,UAAU,OAAO,QAAsB;IAAE,GAAG;IAAO,IAAI,QAAQ;GAAG,CAAC;GAC7F,OAAO,OAAO,UAAU,OAAO,eAAe,WAAW;IACvD;IACA,QAAQ,QAAQ;IAChB,cAAc,QAAQ;GACxB,CAAC;EACH,CAAC;CACL,CAAC;AACH,CAAC,CACH"}
@@ -1,7 +1,11 @@
1
- import { c as SettingsAtom, d as isAcceptedMimeType, o as Backend, r as Create, t as File } from "./chunk-types.mjs";
2
- import { Operation } from "@dxos/compute";
3
- import { Capabilities, Capability } from "@dxos/app-framework";
1
+ import { isAcceptedMimeType } from "./FileLimits.mjs";
2
+ import { Backend, SettingsAtom } from "./FileCapabilities.mjs";
3
+ import { Create } from "./FileOperation.mjs";
4
+ import * as Capability from "@dxos/app-framework/Capability";
5
+ import * as Operation from "@dxos/compute/Operation";
4
6
  import { Blob, Database } from "@dxos/echo";
7
+ import { File } from "@dxos/types";
8
+ import * as Capabilities from "@dxos/app-framework/Capabilities";
5
9
  import * as Effect from "effect/Effect";
6
10
  //#region src/operations/create.ts
7
11
  var UnsupportedFileTypeError = class extends Error {
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-create.mjs","names":[],"sources":["../../src/operations/create.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { Operation } from '@dxos/compute';\nimport { Blob, Database } from '@dxos/echo';\n\nimport { File, FileCapabilities, FileOperation, Settings, isAcceptedMimeType } from '../types';\n\nexport class UnsupportedFileTypeError extends Error {\n constructor(public readonly type: string) {\n super(`Unsupported file type: ${type}`);\n this.name = 'UnsupportedFileTypeError';\n }\n}\n\nexport class FileTooLargeError extends Error {\n constructor(\n public readonly size: number,\n public readonly limit: number = Blob.MAX_INLINE_SIZE,\n ) {\n super(`File is too large: ${size} bytes (limit: ${limit} bytes)`);\n this.name = 'FileTooLargeError';\n }\n}\n\nexport class NoBackendError extends Error {\n constructor() {\n super('No file storage backend is registered.');\n this.name = 'NoBackendError';\n }\n}\n\nexport class FileReadError extends Error {\n constructor(cause: unknown) {\n super('Failed to read file contents.');\n this.name = 'FileReadError';\n this.cause = cause;\n }\n}\n\n/**\n * Resolves the storage name to force for an upload:\n * - the storage name the user explicitly configured in Settings.backend, if it matches a\n * registered {@link FileCapabilities.Backend} descriptor\n * - otherwise `undefined`, leaving `File.fromBytes`'s `storage` option unset so it falls through\n * to the Blob registry's own configured default (edge when configured, inline otherwise)\n * instead of hardcoding `inline`\n *\n * Still requires at least one descriptor to be registered, as a sanity check that the plugin's\n * settings UI has something to show.\n */\nexport const resolveActiveStorage = Effect.gen(function* () {\n const backends = yield* Capability.getAll(FileCapabilities.Backend);\n if (backends.length === 0) {\n return yield* Effect.fail(new NoBackendError());\n }\n\n const settingsAtomOpt = yield* Capability.get(FileCapabilities.SettingsAtom).pipe(Effect.option);\n const registryOpt = yield* Capability.get(Capabilities.AtomRegistry).pipe(Effect.option);\n\n if (settingsAtomOpt._tag === 'Some' && registryOpt._tag === 'Some') {\n const settings = registryOpt.value.get(settingsAtomOpt.value) as Settings.Settings;\n if (settings.backend) {\n const match = backends.find((b) => b.storage === settings.backend);\n if (match) {\n return match.storage;\n }\n }\n }\n\n return undefined;\n});\n\nconst handler: Operation.WithHandler<typeof FileOperation.Create> = FileOperation.Create.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* ({ file, db }) {\n // Validate before hitting the backend so the contract is consistent regardless of backend.\n if (!isAcceptedMimeType(file.type)) {\n return yield* Effect.fail(new UnsupportedFileTypeError(file.type));\n }\n const storage = yield* resolveActiveStorage;\n const bytes = new Uint8Array(\n yield* Effect.tryPromise({\n try: () => file.arrayBuffer(),\n catch: (error) => new FileReadError(error),\n }),\n );\n // The size cap only applies to `inline` storage — `Blob.fromBytes` enforces it internally;\n // other backends scale beyond it.\n const object = yield* File.fromBytes(bytes, {\n name: file.name,\n type: file.type,\n storage,\n }).pipe(\n Effect.provide(Database.layer(db)),\n Effect.catchTag('BlobTooLargeError', () => Effect.fail(new FileTooLargeError(bytes.byteLength))),\n );\n return { object };\n }),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;AAYA,IAAa,2BAAb,cAA8C,MAAM;CACtB;CAA5B,YAAY,MAA8B;EACxC,MAAM,0BAA0B,MAAM;EADZ,KAAA,OAAA;EAE1B,KAAK,OAAO;CACd;AACF;AAEA,IAAa,oBAAb,cAAuC,MAAM;CAEzB;CACA;CAFlB,YACE,MACA,QAAgC,KAAK,iBACrC;EACA,MAAM,sBAAsB,KAAK,iBAAiB,MAAM,QAAQ;EAHhD,KAAA,OAAA;EACA,KAAA,QAAA;EAGhB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,iBAAb,cAAoC,MAAM;CACxC,cAAc;EACZ,MAAM,wCAAwC;EAC9C,KAAK,OAAO;CACd;AACF;AAEA,IAAa,gBAAb,cAAmC,MAAM;CACvC,YAAY,OAAgB;EAC1B,MAAM,+BAA+B;EACrC,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;;;;;;;;;;;;AAaA,IAAa,uBAAuB,OAAO,IAAI,aAAa;CAC1D,MAAM,WAAW,OAAO,WAAW,OAAO,OAAwB;CAClE,IAAI,SAAS,WAAW,GACtB,OAAO,OAAO,OAAO,KAAK,IAAI,eAAe,CAAC;CAGhD,MAAM,kBAAkB,OAAO,WAAW,IAAI,YAA6B,CAAC,CAAC,KAAK,OAAO,MAAM;CAC/F,MAAM,cAAc,OAAO,WAAW,IAAI,aAAa,YAAY,CAAC,CAAC,KAAK,OAAO,MAAM;CAEvF,IAAI,gBAAgB,SAAS,UAAU,YAAY,SAAS,QAAQ;EAClE,MAAM,WAAW,YAAY,MAAM,IAAI,gBAAgB,KAAK;EAC5D,IAAI,SAAS,SAAS;GACpB,MAAM,QAAQ,SAAS,MAAM,MAAM,EAAE,YAAY,SAAS,OAAO;GACjE,IAAI,OACF,OAAO,MAAM;EAEjB;CACF;AAGF,CAAC;AAED,IAAM,UAAA,OAAmF,KACvF,UAAU,YACR,OAAO,WAAW,WAAW,EAAE,MAAM,MAAM;CAEzC,IAAI,CAAC,mBAAmB,KAAK,IAAI,GAC/B,OAAO,OAAO,OAAO,KAAK,IAAI,yBAAyB,KAAK,IAAI,CAAC;CAEnE,MAAM,UAAU,OAAO;CACvB,MAAM,QAAQ,IAAI,WAChB,OAAO,OAAO,WAAW;EACvB,WAAW,KAAK,YAAY;EAC5B,QAAQ,UAAU,IAAI,cAAc,KAAK;CAC3C,CAAC,CACH;CAWA,OAAO,EAAE,QAAA,OARa,KAAK,UAAU,OAAO;EAC1C,MAAM,KAAK;EACX,MAAM,KAAK;EACX;CACF,CAAC,CAAC,CAAC,KACD,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,GACjC,OAAO,SAAS,2BAA2B,OAAO,KAAK,IAAI,kBAAkB,MAAM,UAAU,CAAC,CAAC,CACjG,EACgB;AAClB,CAAC,CACH,CACF"}
1
+ {"version":3,"file":"chunk-create.mjs","names":[],"sources":["../../src/operations/create.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Blob, Database } from '@dxos/echo';\nimport { File } from '@dxos/types';\n\nimport * as FileCapabilities from '../types/FileCapabilities';\nimport * as FileLimits from '../types/FileLimits';\nimport * as FileOperation from '../types/FileOperation';\nimport * as Settings from '../types/Settings';\n\nexport class UnsupportedFileTypeError extends Error {\n constructor(public readonly type: string) {\n super(`Unsupported file type: ${type}`);\n this.name = 'UnsupportedFileTypeError';\n }\n}\n\nexport class FileTooLargeError extends Error {\n constructor(\n public readonly size: number,\n public readonly limit: number = Blob.MAX_INLINE_SIZE,\n ) {\n super(`File is too large: ${size} bytes (limit: ${limit} bytes)`);\n this.name = 'FileTooLargeError';\n }\n}\n\nexport class NoBackendError extends Error {\n constructor() {\n super('No file storage backend is registered.');\n this.name = 'NoBackendError';\n }\n}\n\nexport class FileReadError extends Error {\n constructor(cause: unknown) {\n super('Failed to read file contents.');\n this.name = 'FileReadError';\n this.cause = cause;\n }\n}\n\n/**\n * Resolves the storage name to force for an upload:\n * - the storage name the user explicitly configured in Settings.backend, if it matches a\n * registered {@link FileCapabilities.Backend} descriptor\n * - otherwise `undefined`, leaving `File.fromBytes`'s `storage` option unset so it falls through\n * to the Blob registry's own configured default (edge when configured, inline otherwise)\n * instead of hardcoding `inline`\n *\n * Still requires at least one descriptor to be registered, as a sanity check that the plugin's\n * settings UI has something to show.\n */\nexport const resolveActiveStorage = Effect.gen(function* () {\n const backends = yield* Capability.getAll(FileCapabilities.Backend);\n if (backends.length === 0) {\n return yield* Effect.fail(new NoBackendError());\n }\n\n const settingsAtomOpt = yield* Capability.get(FileCapabilities.SettingsAtom).pipe(Effect.option);\n const registryOpt = yield* Capability.get(Capabilities.AtomRegistry).pipe(Effect.option);\n\n if (settingsAtomOpt._tag === 'Some' && registryOpt._tag === 'Some') {\n const settings = registryOpt.value.get(settingsAtomOpt.value) as Settings.Settings;\n if (settings.backend) {\n const match = backends.find((b) => b.storage === settings.backend);\n if (match) {\n return match.storage;\n }\n }\n }\n\n return undefined;\n});\n\nconst handler: Operation.WithHandler<typeof FileOperation.Create> = FileOperation.Create.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* ({ file, db }) {\n // Validate before hitting the backend so the contract is consistent regardless of backend.\n if (!FileLimits.isAcceptedMimeType(file.type)) {\n return yield* Effect.fail(new UnsupportedFileTypeError(file.type));\n }\n const storage = yield* resolveActiveStorage;\n const bytes = new Uint8Array(\n yield* Effect.tryPromise({\n try: () => file.arrayBuffer(),\n catch: (error) => new FileReadError(error),\n }),\n );\n // The size cap only applies to `inline` storage — `Blob.fromBytes` enforces it internally;\n // other backends scale beyond it.\n const object = yield* File.fromBytes(bytes, {\n name: file.name,\n type: file.type,\n storage,\n }).pipe(\n Effect.provide(Database.layer(db)),\n Effect.catchTag('BlobTooLargeError', () => Effect.fail(new FileTooLargeError(bytes.byteLength))),\n );\n return { object };\n }),\n ),\n);\n\nexport default handler;\n"],"mappings":";;;;;;;;;;AAiBA,IAAa,2BAAb,cAA8C,MAAM;CACtB;CAA5B,YAAY,MAA8B;EACxC,MAAM,0BAA0B,MAAM;EADZ,KAAA,OAAA;EAE1B,KAAK,OAAO;CACd;AACF;AAEA,IAAa,oBAAb,cAAuC,MAAM;CAEzB;CACA;CAFlB,YACE,MACA,QAAgC,KAAK,iBACrC;EACA,MAAM,sBAAsB,KAAK,iBAAiB,MAAM,QAAQ;EAHhD,KAAA,OAAA;EACA,KAAA,QAAA;EAGhB,KAAK,OAAO;CACd;AACF;AAEA,IAAa,iBAAb,cAAoC,MAAM;CACxC,cAAc;EACZ,MAAM,wCAAwC;EAC9C,KAAK,OAAO;CACd;AACF;AAEA,IAAa,gBAAb,cAAmC,MAAM;CACvC,YAAY,OAAgB;EAC1B,MAAM,+BAA+B;EACrC,KAAK,OAAO;EACZ,KAAK,QAAQ;CACf;AACF;;;;;;;;;;;;AAaA,IAAa,uBAAuB,OAAO,IAAI,aAAa;CAC1D,MAAM,WAAW,OAAO,WAAW,OAAO,OAAwB;CAClE,IAAI,SAAS,WAAW,GACtB,OAAO,OAAO,OAAO,KAAK,IAAI,eAAe,CAAC;CAGhD,MAAM,kBAAkB,OAAO,WAAW,IAAI,YAA6B,CAAC,CAAC,KAAK,OAAO,MAAM;CAC/F,MAAM,cAAc,OAAO,WAAW,IAAI,aAAa,YAAY,CAAC,CAAC,KAAK,OAAO,MAAM;CAEvF,IAAI,gBAAgB,SAAS,UAAU,YAAY,SAAS,QAAQ;EAClE,MAAM,WAAW,YAAY,MAAM,IAAI,gBAAgB,KAAK;EAC5D,IAAI,SAAS,SAAS;GACpB,MAAM,QAAQ,SAAS,MAAM,MAAM,EAAE,YAAY,SAAS,OAAO;GACjE,IAAI,OACF,OAAO,MAAM;EAEjB;CACF;AAGF,CAAC;AAED,IAAM,UAAA,OAAmF,KACvF,UAAU,YACR,OAAO,WAAW,WAAW,EAAE,MAAM,MAAM;CAEzC,IAAI,CAAC,mBAA8B,KAAK,IAAI,GAC1C,OAAO,OAAO,OAAO,KAAK,IAAI,yBAAyB,KAAK,IAAI,CAAC;CAEnE,MAAM,UAAU,OAAO;CACvB,MAAM,QAAQ,IAAI,WAChB,OAAO,OAAO,WAAW;EACvB,WAAW,KAAK,YAAY;EAC5B,QAAQ,UAAU,IAAI,cAAc,KAAK;CAC3C,CAAC,CACH;CAWA,OAAO,EAAE,QAAA,OARa,KAAK,UAAU,OAAO;EAC1C,MAAM,KAAK;EACX,MAAM,KAAK;EACX;CACF,CAAC,CAAC,CAAC,KACD,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,GACjC,OAAO,SAAS,2BAA2B,OAAO,KAAK,IAAI,kBAAkB,MAAM,UAAU,CAAC,CAAC,CACjG,EACgB;AAClB,CAAC,CACH,CACF"}
@@ -1,12 +1,14 @@
1
- import { Capabilities, Capability } from "@dxos/app-framework";
1
+ import { Backend } from "./FileCapabilities.mjs";
2
+ import * as Capability from "@dxos/app-framework/Capability";
2
3
  import { Blob } from "@dxos/echo";
3
- import { ClientCapabilities } from "@dxos/plugin-client";
4
- import { FileCapabilities } from "#types";
4
+ import * as ClientCapabilities from "@dxos/plugin-client/ClientCapabilities";
5
5
  import * as Effect from "effect/Effect";
6
6
  //#region src/capabilities/edge-backend.ts
7
7
  var edge_backend_default = Capability.makeModule(Effect.fnUntraced(function* () {
8
- if (!(yield* Capability.get(ClientCapabilities.Client)).config.values.runtime?.services?.edge?.url) return Capability.contributes(Capabilities.Null, null);
9
- return Capability.contributes(FileCapabilities.Backend, {
8
+ const client = yield* ClientCapabilities.Client;
9
+ yield* Effect.promise(() => client.waitUntilInitialized());
10
+ if (!client.config.values.runtime?.services?.edge?.url) return [];
11
+ return Capability.contribute(Backend, {
10
12
  name: "Edge",
11
13
  description: "Store files on the DXOS edge network. Scales beyond the inline size cap.",
12
14
  storage: Blob.Storage.edge
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-edge-backend.mjs","names":[],"sources":["../../src/capabilities/edge-backend.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { Blob } from '@dxos/echo';\nimport { ClientCapabilities } from '@dxos/plugin-client';\n\nimport { FileCapabilities } from '#types';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const client = yield* Capability.get(ClientCapabilities.Client);\n const edgeUrl = client.config.values.runtime?.services?.edge?.url;\n if (!edgeUrl) {\n return Capability.contributes(Capabilities.Null, null);\n }\n\n return Capability.contributes(FileCapabilities.Backend, {\n name: 'Edge',\n description: 'Store files on the DXOS edge network. Scales beyond the inline size cap.',\n storage: Blob.Storage.edge,\n });\n }),\n);\n"],"mappings":";;;;;;AAYA,IAAA,uBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAG7B,IAAI,EADY,OADM,WAAW,IAAI,mBAAmB,MAAM,EAAA,CACvC,OAAO,OAAO,SAAS,UAAU,MAAM,KAE5D,OAAO,WAAW,YAAY,aAAa,MAAM,IAAI;CAGvD,OAAO,WAAW,YAAY,iBAAiB,SAAS;EACtD,MAAM;EACN,aAAa;EACb,SAAS,KAAK,QAAQ;CACxB,CAAC;AACH,CAAC,CACH"}
1
+ {"version":3,"file":"chunk-edge-backend.mjs","names":[],"sources":["../../src/capabilities/edge-backend.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport { Blob } from '@dxos/echo';\nimport * as ClientCapabilities from '@dxos/plugin-client/ClientCapabilities';\n\nimport * as FileCapabilities from '../types/FileCapabilities';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const client = yield* ClientCapabilities.Client;\n // `config` is initialized-only, and this event wave can land before the forked client\n // initialization completes.\n yield* Effect.promise(() => client.waitUntilInitialized());\n const edgeUrl = client.config.values.runtime?.services?.edge?.url;\n if (!edgeUrl) {\n // No edge service configured — skip the declared provide (runtime warns, not fails).\n return [];\n }\n\n return Capability.contribute(FileCapabilities.Backend, {\n name: 'Edge',\n description: 'Store files on the DXOS edge network. Scales beyond the inline size cap.',\n storage: Blob.Storage.edge,\n });\n }),\n);\n"],"mappings":";;;;;;AAYA,IAAA,uBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,MAAM,SAAS,OAAO,mBAAmB;CAGzC,OAAO,OAAO,cAAc,OAAO,qBAAqB,CAAC;CAEzD,IAAI,CADY,OAAO,OAAO,OAAO,SAAS,UAAU,MAAM,KAG5D,OAAO,CAAC;CAGV,OAAO,WAAW,WAAW,SAA0B;EACrD,MAAM;EACN,aAAa;EACb,SAAS,KAAK,QAAQ;CACxB,CAAC;AACH,CAAC,CACH"}
@@ -1,18 +1,18 @@
1
- import { Capabilities, Capability } from "@dxos/app-framework";
1
+ import { Create } from "./FileOperation.mjs";
2
+ import * as Capability from "@dxos/app-framework/Capability";
2
3
  import { Blob, Database } from "@dxos/echo";
3
- import { AppCapabilities } from "@dxos/app-toolkit";
4
- import { FileOperation } from "#types";
4
+ import * as Capabilities from "@dxos/app-framework/Capabilities";
5
+ import * as AppCapabilities from "@dxos/app-toolkit/AppCapabilities";
5
6
  import { EffectEx } from "@dxos/effect";
6
7
  import * as Effect from "effect/Effect";
7
8
  import { SpaceOperation } from "@dxos/plugin-space";
8
9
  import * as Option from "effect/Option";
9
10
  //#region src/capabilities/file-uploader.ts
10
11
  var file_uploader_default = Capability.makeModule(Effect.fnUntraced(function* () {
11
- const capabilities = yield* Capability.Service;
12
- return Capability.contributes(AppCapabilities.FileUploader, (db, file) => {
13
- const { invoke } = capabilities.get(Capabilities.OperationInvoker);
12
+ const { invoke } = yield* Capabilities.OperationInvoker;
13
+ return Capability.contribute(AppCapabilities.FileUploader, (db, file) => {
14
14
  const program = Effect.gen(function* () {
15
- const { object } = yield* invoke(FileOperation.Create, {
15
+ const { object } = yield* invoke(Create, {
16
16
  db,
17
17
  file
18
18
  });
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-file-uploader.mjs","names":[],"sources":["../../src/capabilities/file-uploader.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nimport { Capabilities, Capability } from '@dxos/app-framework';\nimport { AppCapabilities } from '@dxos/app-toolkit';\nimport { Blob, Database } from '@dxos/echo';\nimport { EffectEx } from '@dxos/effect';\nimport { SpaceOperation } from '@dxos/plugin-space';\n\nimport { FileOperation } from '#types';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const capabilities = yield* Capability.Service;\n\n return Capability.contributes(AppCapabilities.FileUploader, (db, file) => {\n const { invoke } = capabilities.get(Capabilities.OperationInvoker);\n const program = Effect.gen(function* () {\n const { object } = yield* invoke(FileOperation.Create, { db, file });\n yield* invoke(SpaceOperation.AddObject, { target: db, object });\n const blob = yield* Database.load(object.data);\n const urlOption = yield* Blob.url(blob).pipe(Effect.provide(Database.layer(db)));\n return {\n name: object.name ?? file.name,\n type: blob.type ?? 'application/octet-stream',\n ...(Option.isSome(urlOption) ? { url: urlOption.value } : {}),\n };\n });\n\n return EffectEx.runAndForwardErrors(program);\n });\n }),\n);\n"],"mappings":";;;;;;;;;AAeA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,MAAM,eAAe,OAAO,WAAW;CAEvC,OAAO,WAAW,YAAY,gBAAgB,eAAe,IAAI,SAAS;EACxE,MAAM,EAAE,WAAW,aAAa,IAAI,aAAa,gBAAgB;EACjE,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,EAAE,WAAW,OAAO,OAAO,cAAc,QAAQ;IAAE;IAAI;GAAK,CAAC;GACnE,OAAO,OAAO,eAAe,WAAW;IAAE,QAAQ;IAAI;GAAO,CAAC;GAC9D,MAAM,OAAO,OAAO,SAAS,KAAK,OAAO,IAAI;GAC7C,MAAM,YAAY,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;GAC/E,OAAO;IACL,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,KAAK,QAAQ;IACnB,GAAI,OAAO,OAAO,SAAS,IAAI,EAAE,KAAK,UAAU,MAAM,IAAI,CAAC;GAC7D;EACF,CAAC;EAED,OAAO,SAAS,oBAAoB,OAAO;CAC7C,CAAC;AACH,CAAC,CACH"}
1
+ {"version":3,"file":"chunk-file-uploader.mjs","names":[],"sources":["../../src/capabilities/file-uploader.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport { Blob, Database } from '@dxos/echo';\nimport { EffectEx } from '@dxos/effect';\nimport { SpaceOperation } from '@dxos/plugin-space';\n\nimport * as FileOperation from '../types/FileOperation';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n const { invoke } = yield* Capabilities.OperationInvoker;\n\n return Capability.contribute(AppCapabilities.FileUploader, (db, file) => {\n const program = Effect.gen(function* () {\n const { object } = yield* invoke(FileOperation.Create, { db, file });\n yield* invoke(SpaceOperation.AddObject, { target: db, object });\n const blob = yield* Database.load(object.data);\n const urlOption = yield* Blob.url(blob).pipe(Effect.provide(Database.layer(db)));\n return {\n name: object.name ?? file.name,\n type: blob.type ?? 'application/octet-stream',\n ...(Option.isSome(urlOption) ? { url: urlOption.value } : {}),\n };\n });\n\n return EffectEx.runAndForwardErrors(program);\n });\n }),\n);\n"],"mappings":";;;;;;;;;;AAgBA,IAAA,wBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,MAAM,EAAE,WAAW,OAAO,aAAa;CAEvC,OAAO,WAAW,WAAW,gBAAgB,eAAe,IAAI,SAAS;EACvE,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,EAAE,WAAW,OAAO,OAAO,QAAsB;IAAE;IAAI;GAAK,CAAC;GACnE,OAAO,OAAO,eAAe,WAAW;IAAE,QAAQ;IAAI;GAAO,CAAC;GAC9D,MAAM,OAAO,OAAO,SAAS,KAAK,OAAO,IAAI;GAC7C,MAAM,YAAY,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;GAC/E,OAAO;IACL,MAAM,OAAO,QAAQ,KAAK;IAC1B,MAAM,KAAK,QAAQ;IACnB,GAAI,OAAO,OAAO,SAAS,IAAI,EAAE,KAAK,UAAU,MAAM,IAAI,CAAC;GAC7D;EACF,CAAC;EAED,OAAO,SAAS,oBAAoB,OAAO;CAC7C,CAAC;AACH,CAAC,CACH"}