@dxos/plugin-file 0.9.1-staging.ee54ba693a → 0.11.0

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 (174) hide show
  1. package/PLUGIN.mdl +86 -77
  2. package/dist/lib/FilePlugin.mjs +37 -0
  3. package/dist/lib/FilePlugin.mjs.map +1 -0
  4. package/dist/lib/FilePlugin.node.mjs +12 -0
  5. package/dist/lib/FilePlugin.node.mjs.map +1 -0
  6. package/dist/lib/capabilities/node.mjs +8 -0
  7. package/dist/lib/capabilities/node.mjs.map +1 -0
  8. package/dist/lib/capabilities.mjs +15 -0
  9. package/dist/lib/capabilities.mjs.map +1 -0
  10. package/dist/lib/chunk-FileArticle.mjs +62 -0
  11. package/dist/lib/chunk-FileArticle.mjs.map +1 -0
  12. package/dist/lib/chunk-create-object.mjs +28 -0
  13. package/dist/lib/chunk-create-object.mjs.map +1 -0
  14. package/dist/lib/chunk-create.mjs +78 -0
  15. package/dist/lib/chunk-create.mjs.map +1 -0
  16. package/dist/lib/chunk-edge-backend.mjs +18 -0
  17. package/dist/lib/chunk-edge-backend.mjs.map +1 -0
  18. package/dist/lib/chunk-file-uploader.mjs +37 -0
  19. package/dist/lib/chunk-file-uploader.mjs.map +1 -0
  20. package/dist/lib/chunk-inline-backend.mjs +19 -0
  21. package/dist/lib/chunk-inline-backend.mjs.map +1 -0
  22. package/dist/lib/chunk-markdown-extension.mjs +182 -0
  23. package/dist/lib/chunk-markdown-extension.mjs.map +1 -0
  24. package/dist/lib/chunk-meta.mjs +44 -0
  25. package/dist/lib/chunk-meta.mjs.map +1 -0
  26. package/dist/lib/chunk-operation-handler.mjs +11 -0
  27. package/dist/lib/chunk-operation-handler.mjs.map +1 -0
  28. package/dist/lib/chunk-react-surface.mjs +55 -0
  29. package/dist/lib/chunk-react-surface.mjs.map +1 -0
  30. package/dist/lib/chunk-read.mjs +32 -0
  31. package/dist/lib/chunk-read.mjs.map +1 -0
  32. package/dist/lib/chunk-settings.mjs +23 -0
  33. package/dist/lib/chunk-settings.mjs.map +1 -0
  34. package/dist/lib/chunk-skill-definition.mjs +10 -0
  35. package/dist/lib/chunk-skill-definition.mjs.map +1 -0
  36. package/dist/lib/chunk-skills.mjs +28 -0
  37. package/dist/lib/chunk-skills.mjs.map +1 -0
  38. package/dist/lib/chunk-types.mjs +98 -0
  39. package/dist/lib/chunk-types.mjs.map +1 -0
  40. package/dist/lib/components.mjs +57 -0
  41. package/dist/lib/components.mjs.map +1 -0
  42. package/dist/lib/containers.mjs +56 -0
  43. package/dist/lib/containers.mjs.map +1 -0
  44. package/dist/lib/index.mjs +4 -0
  45. package/dist/lib/meta.mjs +2 -0
  46. package/dist/lib/operations.mjs +7 -0
  47. package/dist/lib/operations.mjs.map +1 -0
  48. package/dist/lib/plugin.mjs +9 -0
  49. package/dist/lib/plugin.mjs.map +1 -0
  50. package/dist/lib/skills.mjs +2 -0
  51. package/dist/lib/translations.mjs +30 -0
  52. package/dist/lib/translations.mjs.map +1 -0
  53. package/dist/lib/types.mjs +2 -0
  54. package/dist/types/src/FilePlugin.d.ts.map +1 -1
  55. package/dist/types/src/FilePlugin.node.d.ts.map +1 -1
  56. package/dist/types/src/capabilities/FileUploadField.d.ts +12 -0
  57. package/dist/types/src/capabilities/FileUploadField.d.ts.map +1 -0
  58. package/dist/types/src/capabilities/create-object.d.ts +1 -1
  59. package/dist/types/src/capabilities/edge-backend.d.ts +5 -0
  60. package/dist/types/src/capabilities/edge-backend.d.ts.map +1 -0
  61. package/dist/types/src/capabilities/file-uploader.d.ts +1 -1
  62. package/dist/types/src/capabilities/file-uploader.d.ts.map +1 -1
  63. package/dist/types/src/capabilities/index.d.ts +1 -0
  64. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  65. package/dist/types/src/capabilities/inline-backend.d.ts +2 -2
  66. package/dist/types/src/capabilities/inline-backend.d.ts.map +1 -1
  67. package/dist/types/src/capabilities/markdown-extension.d.ts +1 -1
  68. package/dist/types/src/capabilities/node.d.ts +5 -0
  69. package/dist/types/src/capabilities/node.d.ts.map +1 -0
  70. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  71. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  72. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  73. package/dist/types/src/capabilities/settings.d.ts +1 -1
  74. package/dist/types/src/components/FileInput/FileInput.d.ts.map +1 -1
  75. package/dist/types/src/components/FilePreview/FilePreview.d.ts +1 -1
  76. package/dist/types/src/components/FilePreview/FilePreview.d.ts.map +1 -1
  77. package/dist/types/src/containers/FileArticle/FileArticle.d.ts +4 -1
  78. package/dist/types/src/containers/FileArticle/FileArticle.d.ts.map +1 -1
  79. package/dist/types/src/containers/FileSettings/FileSettings.d.ts +5 -3
  80. package/dist/types/src/containers/FileSettings/FileSettings.d.ts.map +1 -1
  81. package/dist/types/src/extensions/image.d.ts +0 -2
  82. package/dist/types/src/extensions/image.d.ts.map +1 -1
  83. package/dist/types/src/operations/create.d.ts +14 -5
  84. package/dist/types/src/operations/create.d.ts.map +1 -1
  85. package/dist/types/src/operations/read.d.ts.map +1 -1
  86. package/dist/types/src/types/FileCapabilities.d.ts +10 -28
  87. package/dist/types/src/types/FileCapabilities.d.ts.map +1 -1
  88. package/dist/types/src/types/Settings.d.ts +1 -1
  89. package/dist/types/src/types/Settings.d.ts.map +1 -1
  90. package/dist/types/src/types/limits.d.ts +0 -1
  91. package/dist/types/src/types/limits.d.ts.map +1 -1
  92. package/dist/types/tsconfig.tsbuildinfo +1 -1
  93. package/dx.config.ts +10 -6
  94. package/package.json +45 -41
  95. package/src/FilePlugin.node.ts +2 -1
  96. package/src/FilePlugin.tsx +8 -1
  97. package/src/capabilities/FileUploadField.tsx +37 -0
  98. package/src/capabilities/edge-backend.ts +27 -0
  99. package/src/capabilities/file-uploader.ts +6 -4
  100. package/src/capabilities/index.ts +1 -0
  101. package/src/capabilities/inline-backend.ts +4 -21
  102. package/src/capabilities/markdown-extension.ts +3 -8
  103. package/src/capabilities/node.ts +16 -0
  104. package/src/capabilities/react-surface.ts +46 -0
  105. package/src/components/FileInput/FileInput.tsx +3 -2
  106. package/src/containers/FileArticle/FileArticle.tsx +49 -42
  107. package/src/containers/FileSettings/FileSettings.tsx +19 -14
  108. package/src/extensions/image.tsx +49 -28
  109. package/src/operations/create.test.ts +122 -32
  110. package/src/operations/create.ts +44 -24
  111. package/src/operations/read.ts +24 -6
  112. package/src/types/FileCapabilities.ts +10 -31
  113. package/src/types/Settings.ts +1 -1
  114. package/src/types/limits.ts +0 -2
  115. package/dist/lib/neutral/FileArticle-YU6NN3KN.mjs +0 -80
  116. package/dist/lib/neutral/FileArticle-YU6NN3KN.mjs.map +0 -7
  117. package/dist/lib/neutral/FilePlugin.mjs +0 -58
  118. package/dist/lib/neutral/FilePlugin.mjs.map +0 -7
  119. package/dist/lib/neutral/FilePlugin.node.mjs +0 -23
  120. package/dist/lib/neutral/FilePlugin.node.mjs.map +0 -7
  121. package/dist/lib/neutral/capabilities/index.mjs +0 -23
  122. package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
  123. package/dist/lib/neutral/chunk-DKGTSUUH.mjs +0 -8
  124. package/dist/lib/neutral/chunk-DKGTSUUH.mjs.map +0 -7
  125. package/dist/lib/neutral/chunk-GMYSEHV4.mjs +0 -40
  126. package/dist/lib/neutral/chunk-GMYSEHV4.mjs.map +0 -7
  127. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
  128. package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
  129. package/dist/lib/neutral/chunk-LBZ4MCLI.mjs +0 -45
  130. package/dist/lib/neutral/chunk-LBZ4MCLI.mjs.map +0 -7
  131. package/dist/lib/neutral/chunk-YODPX62X.mjs +0 -136
  132. package/dist/lib/neutral/chunk-YODPX62X.mjs.map +0 -7
  133. package/dist/lib/neutral/chunk-ZUXUTRAJ.mjs +0 -80
  134. package/dist/lib/neutral/chunk-ZUXUTRAJ.mjs.map +0 -7
  135. package/dist/lib/neutral/components/index.mjs +0 -74
  136. package/dist/lib/neutral/components/index.mjs.map +0 -7
  137. package/dist/lib/neutral/containers/index.mjs +0 -59
  138. package/dist/lib/neutral/containers/index.mjs.map +0 -7
  139. package/dist/lib/neutral/create-IUUG7RI6.mjs +0 -17
  140. package/dist/lib/neutral/create-IUUG7RI6.mjs.map +0 -7
  141. package/dist/lib/neutral/create-object-V667G4ZL.mjs +0 -30
  142. package/dist/lib/neutral/create-object-V667G4ZL.mjs.map +0 -7
  143. package/dist/lib/neutral/file-uploader-BCJH6TUL.mjs +0 -41
  144. package/dist/lib/neutral/file-uploader-BCJH6TUL.mjs.map +0 -7
  145. package/dist/lib/neutral/index.mjs +0 -32
  146. package/dist/lib/neutral/index.mjs.map +0 -7
  147. package/dist/lib/neutral/inline-backend-FGGGDYRB.mjs +0 -37
  148. package/dist/lib/neutral/inline-backend-FGGGDYRB.mjs.map +0 -7
  149. package/dist/lib/neutral/markdown-extension-RA5YNMTW.mjs +0 -230
  150. package/dist/lib/neutral/markdown-extension-RA5YNMTW.mjs.map +0 -7
  151. package/dist/lib/neutral/meta.json +0 -1
  152. package/dist/lib/neutral/meta.mjs +0 -8
  153. package/dist/lib/neutral/meta.mjs.map +0 -7
  154. package/dist/lib/neutral/operation-handler-CPDANWGH.mjs +0 -13
  155. package/dist/lib/neutral/operation-handler-CPDANWGH.mjs.map +0 -7
  156. package/dist/lib/neutral/operations/index.mjs +0 -8
  157. package/dist/lib/neutral/operations/index.mjs.map +0 -7
  158. package/dist/lib/neutral/plugin.mjs +0 -16
  159. package/dist/lib/neutral/plugin.mjs.map +0 -7
  160. package/dist/lib/neutral/react-surface-5BXKSHD2.mjs +0 -60
  161. package/dist/lib/neutral/react-surface-5BXKSHD2.mjs.map +0 -7
  162. package/dist/lib/neutral/read-HG6CSWKR.mjs +0 -28
  163. package/dist/lib/neutral/read-HG6CSWKR.mjs.map +0 -7
  164. package/dist/lib/neutral/settings-RR3RESL2.mjs +0 -28
  165. package/dist/lib/neutral/settings-RR3RESL2.mjs.map +0 -7
  166. package/dist/lib/neutral/skill-definition-YHBGWBUS.mjs +0 -15
  167. package/dist/lib/neutral/skill-definition-YHBGWBUS.mjs.map +0 -7
  168. package/dist/lib/neutral/skills/index.mjs +0 -11
  169. package/dist/lib/neutral/skills/index.mjs.map +0 -7
  170. package/dist/lib/neutral/translations.mjs +0 -36
  171. package/dist/lib/neutral/translations.mjs.map +0 -7
  172. package/dist/lib/neutral/types/index.mjs +0 -22
  173. package/dist/lib/neutral/types/index.mjs.map +0 -7
  174. package/src/capabilities/react-surface.tsx +0 -61
@@ -1,80 +0,0 @@
1
- import "./chunk-J5LGTIGS.mjs";
2
-
3
- // src/containers/FileArticle/FileArticle.tsx
4
- import React, { useEffect, useState } from "react";
5
- import { useCapabilities } from "@dxos/app-framework/ui";
6
- import { getSpace } from "@dxos/react-client/echo";
7
- import { Panel } from "@dxos/react-ui";
8
- import { FilePreview } from "#components";
9
- import { FileCapabilities } from "#types";
10
- var FileArticle = ({ role, subject: file }) => {
11
- const resolvers = useCapabilities(FileCapabilities.UrlResolver);
12
- const [renderUrl, setRenderUrl] = useState(void 0);
13
- useEffect(() => {
14
- const { data } = file;
15
- if (data._tag === "inline") {
16
- const url = URL.createObjectURL(new Blob([
17
- data.bytes
18
- ], {
19
- type: file.type
20
- }));
21
- setRenderUrl(url);
22
- return () => URL.revokeObjectURL(url);
23
- }
24
- let cancelled = false;
25
- let createdBlobUrl;
26
- if (/^(?:https?|data|blob):/i.test(data.url)) {
27
- setRenderUrl(data.url);
28
- } else {
29
- const resolver = resolvers.find((r) => r.test(data.url));
30
- if (!resolver) {
31
- setRenderUrl(void 0);
32
- return;
33
- }
34
- setRenderUrl(void 0);
35
- void resolver.resolve(data.url, file, getSpace(file)).then((url) => {
36
- if (cancelled) {
37
- if (url?.startsWith("blob:")) {
38
- URL.revokeObjectURL(url);
39
- }
40
- return;
41
- }
42
- if (url?.startsWith("blob:")) {
43
- createdBlobUrl = url;
44
- }
45
- setRenderUrl(url);
46
- }).catch(() => {
47
- if (!cancelled) {
48
- setRenderUrl(void 0);
49
- }
50
- });
51
- }
52
- return () => {
53
- cancelled = true;
54
- if (createdBlobUrl) {
55
- URL.revokeObjectURL(createdBlobUrl);
56
- }
57
- };
58
- }, [
59
- file,
60
- file.data,
61
- file.type,
62
- resolvers
63
- ]);
64
- if (!renderUrl) {
65
- return null;
66
- }
67
- return /* @__PURE__ */ React.createElement(Panel.Root, {
68
- role,
69
- className: "dx-document"
70
- }, /* @__PURE__ */ React.createElement(Panel.Content, {
71
- asChild: true
72
- }, /* @__PURE__ */ React.createElement(FilePreview, {
73
- type: file.type,
74
- url: renderUrl
75
- })));
76
- };
77
- export {
78
- FileArticle as default
79
- };
80
- //# sourceMappingURL=FileArticle-YU6NN3KN.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/containers/FileArticle/FileArticle.tsx"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useEffect, useState } from 'react';\n\nimport { useCapabilities } from '@dxos/app-framework/ui';\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { getSpace } from '@dxos/react-client/echo';\nimport { Panel } from '@dxos/react-ui';\n\nimport { FilePreview } from '#components';\nimport { File, FileCapabilities } from '#types';\n\nexport type FileArticleProps = AppSurface.ObjectArticleProps<File.File>;\n\nexport const FileArticle = ({ role, subject: file }: FileArticleProps) => {\n const resolvers = useCapabilities(FileCapabilities.UrlResolver);\n const [renderUrl, setRenderUrl] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n const { data } = file;\n if (data._tag === 'inline') {\n const url = URL.createObjectURL(new Blob([data.bytes as BlobPart], { type: file.type }));\n setRenderUrl(url);\n return () => URL.revokeObjectURL(url);\n }\n\n // External URL: pass through `http(s):`/`data:`/`blob:` directly; otherwise dispatch to a resolver.\n let cancelled = false;\n let createdBlobUrl: string | undefined;\n\n if (/^(?:https?|data|blob):/i.test(data.url)) {\n setRenderUrl(data.url);\n } else {\n const resolver = resolvers.find((r) => r.test(data.url));\n if (!resolver) {\n setRenderUrl(undefined);\n return;\n }\n setRenderUrl(undefined);\n void resolver\n .resolve(data.url, file, getSpace(file))\n .then((url) => {\n if (cancelled) {\n if (url?.startsWith('blob:')) {\n URL.revokeObjectURL(url);\n }\n return;\n }\n if (url?.startsWith('blob:')) {\n createdBlobUrl = url;\n }\n setRenderUrl(url);\n })\n .catch(() => {\n if (!cancelled) {\n setRenderUrl(undefined);\n }\n });\n }\n\n return () => {\n cancelled = true;\n if (createdBlobUrl) {\n URL.revokeObjectURL(createdBlobUrl);\n }\n };\n }, [file, file.data, file.type, resolvers]);\n\n if (!renderUrl) {\n return null;\n }\n\n return (\n <Panel.Root role={role} className='dx-document'>\n <Panel.Content asChild>\n <FilePreview type={file.type} url={renderUrl} />\n </Panel.Content>\n </Panel.Root>\n );\n};\n\nexport default FileArticle;\n"],
5
- "mappings": ";;;AAIA,OAAOA,SAASC,WAAWC,gBAAgB;AAE3C,SAASC,uBAAuB;AAEhC,SAASC,gBAAgB;AACzB,SAASC,aAAa;AAEtB,SAASC,mBAAmB;AAC5B,SAAeC,wBAAwB;AAIhC,IAAMC,cAAc,CAAC,EAAEC,MAAMC,SAASC,KAAI,MAAoB;AACnE,QAAMC,YAAYT,gBAAgBI,iBAAiBM,WAAW;AAC9D,QAAM,CAACC,WAAWC,YAAAA,IAAgBb,SAA6Bc,MAAAA;AAE/Df,YAAU,MAAA;AACR,UAAM,EAAEgB,KAAI,IAAKN;AACjB,QAAIM,KAAKC,SAAS,UAAU;AAC1B,YAAMC,MAAMC,IAAIC,gBAAgB,IAAIC,KAAK;QAACL,KAAKM;SAAoB;QAAEC,MAAMb,KAAKa;MAAK,CAAA,CAAA;AACrFT,mBAAaI,GAAAA;AACb,aAAO,MAAMC,IAAIK,gBAAgBN,GAAAA;IACnC;AAGA,QAAIO,YAAY;AAChB,QAAIC;AAEJ,QAAI,0BAA0BC,KAAKX,KAAKE,GAAG,GAAG;AAC5CJ,mBAAaE,KAAKE,GAAG;IACvB,OAAO;AACL,YAAMU,WAAWjB,UAAUkB,KAAK,CAACC,MAAMA,EAAEH,KAAKX,KAAKE,GAAG,CAAA;AACtD,UAAI,CAACU,UAAU;AACbd,qBAAaC,MAAAA;AACb;MACF;AACAD,mBAAaC,MAAAA;AACb,WAAKa,SACFG,QAAQf,KAAKE,KAAKR,MAAMP,SAASO,IAAAA,CAAAA,EACjCsB,KAAK,CAACd,QAAAA;AACL,YAAIO,WAAW;AACb,cAAIP,KAAKe,WAAW,OAAA,GAAU;AAC5Bd,gBAAIK,gBAAgBN,GAAAA;UACtB;AACA;QACF;AACA,YAAIA,KAAKe,WAAW,OAAA,GAAU;AAC5BP,2BAAiBR;QACnB;AACAJ,qBAAaI,GAAAA;MACf,CAAA,EACCgB,MAAM,MAAA;AACL,YAAI,CAACT,WAAW;AACdX,uBAAaC,MAAAA;QACf;MACF,CAAA;IACJ;AAEA,WAAO,MAAA;AACLU,kBAAY;AACZ,UAAIC,gBAAgB;AAClBP,YAAIK,gBAAgBE,cAAAA;MACtB;IACF;EACF,GAAG;IAAChB;IAAMA,KAAKM;IAAMN,KAAKa;IAAMZ;GAAU;AAE1C,MAAI,CAACE,WAAW;AACd,WAAO;EACT;AAEA,SACE,sBAAA,cAACT,MAAM+B,MAAI;IAAC3B;IAAY4B,WAAU;KAChC,sBAAA,cAAChC,MAAMiC,SAAO;IAACC,SAAAA;KACb,sBAAA,cAACjC,aAAAA;IAAYkB,MAAMb,KAAKa;IAAML,KAAKL;;AAI3C;",
6
- "names": ["React", "useEffect", "useState", "useCapabilities", "getSpace", "Panel", "FilePreview", "FileCapabilities", "FileArticle", "role", "subject", "file", "resolvers", "UrlResolver", "renderUrl", "setRenderUrl", "undefined", "data", "_tag", "url", "URL", "createObjectURL", "Blob", "bytes", "type", "revokeObjectURL", "cancelled", "createdBlobUrl", "test", "resolver", "find", "r", "resolve", "then", "startsWith", "catch", "Root", "className", "Content", "asChild"]
7
- }
@@ -1,58 +0,0 @@
1
- import "./chunk-J5LGTIGS.mjs";
2
-
3
- // src/FilePlugin.tsx
4
- import { Plugin } from "@dxos/app-framework";
5
- import { AppActivationEvents, AppPlugin } from "@dxos/app-toolkit";
6
- import { ClientEvents } from "@dxos/plugin-client";
7
- import { MarkdownEvents } from "@dxos/plugin-markdown";
8
- import { CreateObject, FileUploader, InlineBackend, Markdown, OperationHandler, ReactSurface, Settings, SkillDefinition } from "#capabilities";
9
- import { meta } from "#meta";
10
- import { translations } from "#translations";
11
- import { File } from "#types";
12
-
13
- // raw-loader:/__w/dxos/dxos/packages/plugins/plugin-file/PLUGIN.mdl
14
- var PLUGIN_default = "---\nid: org.dxos.plugin.file\nname: FilePlugin\nversion: 0.1.0\n---\n\nFilePlugin enables DXOS Composer to store and preview binary files \u2014 images, videos, and PDFs \u2014 as first-class ECHO objects.\nUploaded bytes are routed through a pluggable backend system: the built-in `inline` backend serialises the file directly\nonto the ECHO document, while external backends (e.g. WNFS) can be contributed by other plugins.\nA URL-resolver capability lets external-storage backends convert opaque storage URIs into renderable blob, data, or HTTP URLs\nat view time, keeping the ECHO object schema backend-agnostic.\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 FileDataInline\n desc: File bytes stored directly on the ECHO object.\n fields:\n _tag: 'inline'\n bytes: Uint8Array\n```\n\n```mdl\ntype FileDataExternal\n desc: File bytes stored outside ECHO; referenced by URL.\n fields:\n _tag: 'external'\n url: string\n cid?: string # optional content-addressed identifier\n```\n\n```mdl\ntype FileData\n desc: Discriminated union of inline and external storage.\n literals: FileDataInline | FileDataExternal\n```\n\n```mdl\ntype File\n desc: ECHO object (typename dxos.org.type.file) representing an uploaded binary asset.\n fields:\n name?: string\n type: string # MIME type\n size: number # byte count\n data: FileData\n timestamp?: string # ISO 8601 upload time\n```\n\n```mdl\ntype UploadResult\n desc: Normalised return value from a Backend.upload call.\n fields:\n name: string\n type: string\n size: number\n data: FileData\n```\n\n```mdl\ntype Settings\n desc: Per-user plugin settings stored in the ECHO space.\n fields:\n backend?: string # active backend id; 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 blob:, data:, or http(s): URL\n layout: |\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 <img> / <video> / <iframe> \u2502\n \u2502 or [Download file] link \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\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 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 [ Drop file or click here ] \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\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 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 Storage backend: [select \u25BC] \u2502\n \u2502 (one row per registered \u2502\n \u2502 backend with description) \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n```mdl\ncomponent FileArticle\n desc: |\n Full-viewport article container rendered for article, section, and slide\n roles. Resolves a renderable URL from the File object via inline blob\n conversion or registered UrlResolver capabilities, then delegates to\n FilePreview. Shows an empty state while the URL is resolving.\n props:\n role: AppSurface.Role\n subject: File\n layout: |\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 \u2502\n \u2502 FilePreview \u2502\n \u2502 (fills container) \u2502\n \u2502 \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\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 (MIME type and size), routes the upload to the\n active Backend capability, and constructs a File ECHO object from the result.\n Does not add the object to the space \u2014 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\n NoBackendError: no Backend 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 for the inline backend.\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, url/cid)\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\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 Backend capability. Multiple backends\n may be registered simultaneously.\n\n req F-2.2: The inline backend MUST always be registered by FilePlugin itself.\n It serialises bytes directly onto the ECHO object.\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 UrlResolver capability allows external backends to convert an\n opaque storage URI (e.g. wnfs://\u2026) into a renderable URL at view time.\n FileArticle iterates registered resolvers and uses the first that matches.\n```\n\n```mdl\nfeat F-3: File preview\n\n req F-3.1: FileArticle MUST resolve a renderable URL before rendering\n FilePreview. For inline files a blob: URL is created from the stored bytes\n and revoked on unmount.\n\n req F-3.2: FilePreview MUST render the appropriate element for each MIME class:\n image/* \u2192 <img>, video/* \u2192 <video controls>, application/pdf \u2192 <iframe>,\n other \u2192 <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```\n\n```mdl\nfeat F-5: Settings\n\n req F-5.1: The Settings panel MUST list all registered backends with their\n 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 backend is registered\n when: user uploads a 1 MB PNG via the Create Object form\n then:\n - op:Create returns a File 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 registered, 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 with data._tag === 'inline' and type === 'image/png'\n when: FileArticle is rendered\n then:\n - a blob: URL is created from File.data.bytes\n - FilePreview renders an <img> element with that URL\n - the blob: URL is revoked on unmount\n```\n\n```mdl\ntest T-5: Preview PDF\n given: a File with type === 'application/pdf' and a resolved HTTP 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 WNFS backend 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 URL resolved by UrlResolver\n given: a File with data._tag === 'external' and data.url === 'wnfs://cid/file.jpg'\n and: a UrlResolver capability registered that handles 'wnfs://' URIs\n when: FileArticle is rendered\n then:\n - UrlResolver.resolve is called with the wnfs:// URL\n - FilePreview receives the resolved renderable URL\n```\n\n```mdl\ntest T-8: No backend error\n given: no Backend 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";
15
-
16
- // src/FilePlugin.tsx
17
- var FilePlugin = Plugin.define(meta).pipe(AppPlugin.addSkillDefinitionModule({
18
- activate: SkillDefinition
19
- }), AppPlugin.addCreateObjectModule({
20
- activate: CreateObject
21
- }), AppPlugin.addOperationHandlerModule({
22
- activate: OperationHandler
23
- }), AppPlugin.addSchemaModule({
24
- schema: [
25
- File.File
26
- ]
27
- }), AppPlugin.addSettingsModule({
28
- activate: Settings
29
- }), AppPlugin.addSurfaceModule({
30
- activate: ReactSurface
31
- }), AppPlugin.addTranslationsModule({
32
- translations
33
- }), Plugin.addModule({
34
- id: "inline-backend",
35
- activatesOn: AppActivationEvents.SetupSchema,
36
- activate: InlineBackend
37
- }), Plugin.addModule({
38
- id: "file-uploader",
39
- activatesOn: ClientEvents.ClientReady,
40
- activate: FileUploader
41
- }), Plugin.addModule({
42
- id: "markdown",
43
- activatesOn: MarkdownEvents.SetupExtensions,
44
- activate: Markdown
45
- }), AppPlugin.addPluginAssetModule({
46
- asset: {
47
- pluginId: meta.profile.key,
48
- path: "PLUGIN.mdl",
49
- content: PLUGIN_default,
50
- mimeType: "application/x-mdl"
51
- }
52
- }), Plugin.make);
53
- var FilePlugin_default = FilePlugin;
54
- export {
55
- FilePlugin,
56
- FilePlugin_default as default
57
- };
58
- //# sourceMappingURL=FilePlugin.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/FilePlugin.tsx", "raw-loader:/__w/dxos/dxos/packages/plugins/plugin-file/PLUGIN.mdl"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';\nimport { ClientEvents } from '@dxos/plugin-client';\nimport { MarkdownEvents } from '@dxos/plugin-markdown';\n\nimport {\n CreateObject,\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] }),\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: '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", "---\nid: org.dxos.plugin.file\nname: FilePlugin\nversion: 0.1.0\n---\n\nFilePlugin enables DXOS Composer to store and preview binary files \u2014 images, videos, and PDFs \u2014 as first-class ECHO objects.\nUploaded bytes are routed through a pluggable backend system: the built-in `inline` backend serialises the file directly\nonto the ECHO document, while external backends (e.g. WNFS) can be contributed by other plugins.\nA URL-resolver capability lets external-storage backends convert opaque storage URIs into renderable blob, data, or HTTP URLs\nat view time, keeping the ECHO object schema backend-agnostic.\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 FileDataInline\n desc: File bytes stored directly on the ECHO object.\n fields:\n _tag: 'inline'\n bytes: Uint8Array\n```\n\n```mdl\ntype FileDataExternal\n desc: File bytes stored outside ECHO; referenced by URL.\n fields:\n _tag: 'external'\n url: string\n cid?: string # optional content-addressed identifier\n```\n\n```mdl\ntype FileData\n desc: Discriminated union of inline and external storage.\n literals: FileDataInline | FileDataExternal\n```\n\n```mdl\ntype File\n desc: ECHO object (typename dxos.org.type.file) representing an uploaded binary asset.\n fields:\n name?: string\n type: string # MIME type\n size: number # byte count\n data: FileData\n timestamp?: string # ISO 8601 upload time\n```\n\n```mdl\ntype UploadResult\n desc: Normalised return value from a Backend.upload call.\n fields:\n name: string\n type: string\n size: number\n data: FileData\n```\n\n```mdl\ntype Settings\n desc: Per-user plugin settings stored in the ECHO space.\n fields:\n backend?: string # active backend id; 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 blob:, data:, or http(s): URL\n layout: |\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 <img> / <video> / <iframe> \u2502\n \u2502 or [Download file] link \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\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 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 [ Drop file or click here ] \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\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 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 Storage backend: [select \u25BC] \u2502\n \u2502 (one row per registered \u2502\n \u2502 backend with description) \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n```mdl\ncomponent FileArticle\n desc: |\n Full-viewport article container rendered for article, section, and slide\n roles. Resolves a renderable URL from the File object via inline blob\n conversion or registered UrlResolver capabilities, then delegates to\n FilePreview. Shows an empty state while the URL is resolving.\n props:\n role: AppSurface.Role\n subject: File\n layout: |\n \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n \u2502 \u2502\n \u2502 FilePreview \u2502\n \u2502 (fills container) \u2502\n \u2502 \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\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 (MIME type and size), routes the upload to the\n active Backend capability, and constructs a File ECHO object from the result.\n Does not add the object to the space \u2014 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\n NoBackendError: no Backend 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 for the inline backend.\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, url/cid)\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\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 Backend capability. Multiple backends\n may be registered simultaneously.\n\n req F-2.2: The inline backend MUST always be registered by FilePlugin itself.\n It serialises bytes directly onto the ECHO object.\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 UrlResolver capability allows external backends to convert an\n opaque storage URI (e.g. wnfs://\u2026) into a renderable URL at view time.\n FileArticle iterates registered resolvers and uses the first that matches.\n```\n\n```mdl\nfeat F-3: File preview\n\n req F-3.1: FileArticle MUST resolve a renderable URL before rendering\n FilePreview. For inline files a blob: URL is created from the stored bytes\n and revoked on unmount.\n\n req F-3.2: FilePreview MUST render the appropriate element for each MIME class:\n image/* \u2192 <img>, video/* \u2192 <video controls>, application/pdf \u2192 <iframe>,\n other \u2192 <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```\n\n```mdl\nfeat F-5: Settings\n\n req F-5.1: The Settings panel MUST list all registered backends with their\n 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 backend is registered\n when: user uploads a 1 MB PNG via the Create Object form\n then:\n - op:Create returns a File 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 registered, 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 with data._tag === 'inline' and type === 'image/png'\n when: FileArticle is rendered\n then:\n - a blob: URL is created from File.data.bytes\n - FilePreview renders an <img> element with that URL\n - the blob: URL is revoked on unmount\n```\n\n```mdl\ntest T-5: Preview PDF\n given: a File with type === 'application/pdf' and a resolved HTTP 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 WNFS backend 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 URL resolved by UrlResolver\n given: a File with data._tag === 'external' and data.url === 'wnfs://cid/file.jpg'\n and: a UrlResolver capability registered that handles 'wnfs://' URIs\n when: FileArticle is rendered\n then:\n - UrlResolver.resolve is called with the wnfs:// URL\n - FilePreview receives the resolved renderable URL\n```\n\n```mdl\ntest T-8: No backend error\n given: no Backend 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"],
5
- "mappings": ";;;AAIA,SAASA,cAAc;AACvB,SAASC,qBAAqBC,iBAAiB;AAC/C,SAASC,oBAAoB;AAC7B,SAASC,sBAAsB;AAE/B,SACEC,cACAC,cACAC,eACAC,UACAC,kBACAC,cACAC,UACAC,uBACK;AACP,SAASC,YAAY;AACrB,SAASC,oBAAoB;AAC7B,SAASC,YAAY;;;ACrBrB;;;AD0BO,IAAMC,aAAaC,OAAOC,OAAOC,IAAAA,EAAMC,KAC5CC,UAAUC,yBAAyB;EAAEC,UAAUC;AAAgB,CAAA,GAC/DH,UAAUI,sBAAsB;EAAEF,UAAUG;AAAa,CAAA,GACzDL,UAAUM,0BAA0B;EAAEJ,UAAUK;AAAiB,CAAA,GACjEP,UAAUQ,gBAAgB;EAAEC,QAAQ;IAACC,KAAKA;;AAAM,CAAA,GAChDV,UAAUW,kBAAkB;EAAET,UAAUU;AAAS,CAAA,GACjDZ,UAAUa,iBAAiB;EAAEX,UAAUY;AAAa,CAAA,GACpDd,UAAUe,sBAAsB;EAAEC;AAAa,CAAA,GAC/CpB,OAAOqB,UAAU;EACfC,IAAI;EACJC,aAAaC,oBAAoBC;EACjCnB,UAAUoB;AACZ,CAAA,GACA1B,OAAOqB,UAAU;EACfC,IAAI;EACJC,aAAaI,aAAaC;EAC1BtB,UAAUuB;AACZ,CAAA,GACA7B,OAAOqB,UAAU;EACfC,IAAI;EACJC,aAAaO,eAAeC;EAC5BzB,UAAU0B;AACZ,CAAA,GACA5B,UAAU6B,qBAAqB;EAC7BC,OAAO;IAAEC,UAAUjC,KAAKkC,QAAQC;IAAKC,MAAM;IAAcC,SAASC;IAAYC,UAAU;EAAoB;AAC9G,CAAA,GACAzC,OAAO0C,IAAI;AAGb,IAAA,qBAAe3C;",
6
- "names": ["Plugin", "AppActivationEvents", "AppPlugin", "ClientEvents", "MarkdownEvents", "CreateObject", "FileUploader", "InlineBackend", "Markdown", "OperationHandler", "ReactSurface", "Settings", "SkillDefinition", "meta", "translations", "File", "FilePlugin", "Plugin", "define", "meta", "pipe", "AppPlugin", "addSkillDefinitionModule", "activate", "SkillDefinition", "addCreateObjectModule", "CreateObject", "addOperationHandlerModule", "OperationHandler", "addSchemaModule", "schema", "File", "addSettingsModule", "Settings", "addSurfaceModule", "ReactSurface", "addTranslationsModule", "translations", "addModule", "id", "activatesOn", "AppActivationEvents", "SetupSchema", "InlineBackend", "ClientEvents", "ClientReady", "FileUploader", "MarkdownEvents", "SetupExtensions", "Markdown", "addPluginAssetModule", "asset", "pluginId", "profile", "key", "path", "content", "pluginSpec", "mimeType", "make"]
7
- }
@@ -1,23 +0,0 @@
1
- import "./chunk-J5LGTIGS.mjs";
2
-
3
- // src/FilePlugin.node.ts
4
- import { Plugin } from "@dxos/app-framework";
5
- import { AppPlugin } from "@dxos/app-toolkit";
6
- import { CreateObject, OperationHandler } from "#capabilities";
7
- import { meta } from "#meta";
8
- import { File } from "#types";
9
- var FilePlugin = Plugin.define(meta).pipe(AppPlugin.addCreateObjectModule({
10
- activate: CreateObject
11
- }), AppPlugin.addOperationHandlerModule({
12
- activate: OperationHandler
13
- }), AppPlugin.addSchemaModule({
14
- schema: [
15
- File.File
16
- ]
17
- }), Plugin.make);
18
- var FilePlugin_node_default = FilePlugin;
19
- export {
20
- FilePlugin,
21
- FilePlugin_node_default as default
22
- };
23
- //# sourceMappingURL=FilePlugin.node.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/FilePlugin.node.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\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] }),\n Plugin.make,\n);\n\nexport default FilePlugin;\n"],
5
- "mappings": ";;;AAIA,SAASA,cAAc;AACvB,SAASC,iBAAiB;AAE1B,SAASC,cAAcC,wBAAwB;AAC/C,SAASC,YAAY;AACrB,SAASC,YAAY;AAEd,IAAMC,aAAaN,OAAOO,OAAOH,IAAAA,EAAMI,KAC5CP,UAAUQ,sBAAsB;EAAEC,UAAUR;AAAa,CAAA,GACzDD,UAAUU,0BAA0B;EAAED,UAAUP;AAAiB,CAAA,GACjEF,UAAUW,gBAAgB;EAAEC,QAAQ;IAACR,KAAKA;;AAAM,CAAA,GAChDL,OAAOc,IAAI;AAGb,IAAA,0BAAeR;",
6
- "names": ["Plugin", "AppPlugin", "CreateObject", "OperationHandler", "meta", "File", "FilePlugin", "define", "pipe", "addCreateObjectModule", "activate", "addOperationHandlerModule", "addSchemaModule", "schema", "make"]
7
- }
@@ -1,23 +0,0 @@
1
- import "../chunk-J5LGTIGS.mjs";
2
-
3
- // src/capabilities/index.ts
4
- import { Capability } from "@dxos/app-framework";
5
- var SkillDefinition = Capability.lazy("SkillDefinition", () => import("../skill-definition-YHBGWBUS.mjs"));
6
- var CreateObject = Capability.lazy("CreateObject", () => import("../create-object-V667G4ZL.mjs"));
7
- var FileUploader = Capability.lazy("FileUploader", () => import("../file-uploader-BCJH6TUL.mjs"));
8
- var InlineBackend = Capability.lazy("InlineBackend", () => import("../inline-backend-FGGGDYRB.mjs"));
9
- var Markdown = Capability.lazy("MarkdownExtension", () => import("../markdown-extension-RA5YNMTW.mjs"));
10
- var OperationHandler = Capability.lazy("OperationHandler", () => import("../operation-handler-CPDANWGH.mjs"));
11
- var ReactSurface = Capability.lazy("ReactSurface", () => import("../react-surface-5BXKSHD2.mjs"));
12
- var Settings = Capability.lazy("Settings", () => import("../settings-RR3RESL2.mjs"));
13
- export {
14
- CreateObject,
15
- FileUploader,
16
- InlineBackend,
17
- Markdown,
18
- OperationHandler,
19
- ReactSurface,
20
- Settings,
21
- SkillDefinition
22
- };
23
- //# sourceMappingURL=index.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/capabilities/index.ts"],
4
- "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 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"],
5
- "mappings": ";;;AAIA,SAASA,kBAAkB;AAGpB,IAAMC,kBAAkBD,WAAWE,KAAK,mBAAmB,MAAM,OAAO,kCAAA,CAAA;AACxE,IAAMC,eAAeH,WAAWE,KAAK,gBAAgB,MAAM,OAAO,+BAAA,CAAA;AAClE,IAAME,eAAeJ,WAAWE,KAAK,gBAAgB,MAAM,OAAO,+BAAA,CAAA;AAClE,IAAMG,gBAAgBL,WAAWE,KAAK,iBAAiB,MAAM,OAAO,gCAAA,CAAA;AACpE,IAAMI,WAAWN,WAAWE,KAAK,qBAAqB,MAAM,OAAO,oCAAA,CAAA;AACnE,IAAMK,mBAAmBP,WAAWE,KACzC,oBACA,MAAM,OAAO,mCAAA,CAAA;AAER,IAAMM,eAAeR,WAAWE,KAAK,gBAAgB,MAAM,OAAO,+BAAA,CAAA;AAClE,IAAMO,WAAWT,WAAWE,KAAK,YAAY,MAAM,OAAO,0BAAA,CAAA;",
6
- "names": ["Capability", "SkillDefinition", "lazy", "CreateObject", "FileUploader", "InlineBackend", "Markdown", "OperationHandler", "ReactSurface", "Settings"]
7
- }
@@ -1,8 +0,0 @@
1
- // src/operations/index.ts
2
- import { OperationHandlerSet } from "@dxos/compute";
3
- var FileOperationHandlerSet = OperationHandlerSet.lazy(() => import("./create-IUUG7RI6.mjs"), () => import("./read-HG6CSWKR.mjs"));
4
-
5
- export {
6
- FileOperationHandlerSet
7
- };
8
- //# sourceMappingURL=chunk-DKGTSUUH.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/operations/index.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { OperationHandlerSet } from '@dxos/compute';\n\nexport const FileOperationHandlerSet = OperationHandlerSet.lazy(\n () => import('./create'),\n () => import('./read'),\n);\n"],
5
- "mappings": ";AAIA,SAASA,2BAA2B;AAE7B,IAAMC,0BAA0BD,oBAAoBE,KACzD,MAAM,OAAO,uBAAA,GACb,MAAM,OAAO,qBAAA,CAAA;",
6
- "names": ["OperationHandlerSet", "FileOperationHandlerSet", "lazy"]
7
- }
@@ -1,40 +0,0 @@
1
- import {
2
- FileOperation_exports
3
- } from "./chunk-YODPX62X.mjs";
4
-
5
- // src/skills/file-skill.ts
6
- import { Skill, Template } from "@dxos/compute";
7
- import { trim } from "@dxos/util";
8
- var SKILL_KEY = "org.dxos.skill.file";
9
- var make = () => Skill.make({
10
- key: SKILL_KEY,
11
- name: "File",
12
- description: "Read the contents of files (images, videos, PDFs) as File content blocks.",
13
- tools: Skill.toolDefinitions({
14
- operations: [
15
- FileOperation_exports.Read
16
- ]
17
- }),
18
- instructions: Template.make({
19
- source: trim`
20
- {{! File }}
21
-
22
- You can read the contents of files.
23
- Calling the read tool returns the file contents as a File content block (a data URL for
24
- inline files, the original URL for external files). The model receives the file natively
25
- and can describe, transcribe, or otherwise reason over its contents.
26
- `
27
- }),
28
- agentCanEnable: true
29
- });
30
- var skill = {
31
- key: SKILL_KEY,
32
- make
33
- };
34
- var file_skill_default = skill;
35
-
36
- export {
37
- SKILL_KEY,
38
- file_skill_default
39
- };
40
- //# sourceMappingURL=chunk-GMYSEHV4.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/skills/file-skill.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Skill, Template } from '@dxos/compute';\nimport { trim } from '@dxos/util';\n\nimport { FileOperation } from '../types';\n\nexport const SKILL_KEY = 'org.dxos.skill.file';\n\nconst make = () =>\n Skill.make({\n key: SKILL_KEY,\n name: 'File',\n description: 'Read the contents of files (images, videos, PDFs) as File content blocks.',\n tools: Skill.toolDefinitions({\n operations: [FileOperation.Read],\n }),\n instructions: Template.make({\n source: trim`\n {{! File }}\n\n You can read the contents of files.\n Calling the read tool returns the file contents as a File content block (a data URL for\n inline files, the original URL for external files). The model receives the file natively\n and can describe, transcribe, or otherwise reason over its contents.\n `,\n }),\n agentCanEnable: true,\n });\n\nconst skill: Skill.Definition = {\n key: SKILL_KEY,\n make,\n};\n\nexport default skill;\n"],
5
- "mappings": ";;;;;AAIA,SAASA,OAAOC,gBAAgB;AAChC,SAASC,YAAY;AAId,IAAMC,YAAY;AAEzB,IAAMC,OAAO,MACXC,MAAMD,KAAK;EACTE,KAAKH;EACLI,MAAM;EACNC,aAAa;EACbC,OAAOJ,MAAMK,gBAAgB;IAC3BC,YAAY;MAACC,sBAAcC;;EAC7B,CAAA;EACAC,cAAcC,SAASX,KAAK;IAC1BY,QAAQC;;;;;;;;EAQV,CAAA;EACAC,gBAAgB;AAClB,CAAA;AAEF,IAAMC,QAA0B;EAC9Bb,KAAKH;EACLC;AACF;AAEA,IAAA,qBAAee;",
6
- "names": ["Skill", "Template", "trim", "SKILL_KEY", "make", "Skill", "key", "name", "description", "tools", "toolDefinitions", "operations", "FileOperation", "Read", "instructions", "Template", "source", "trim", "agentCanEnable", "skill"]
7
- }
@@ -1,10 +0,0 @@
1
- var __defProp = Object.defineProperty;
2
- var __export = (target, all) => {
3
- for (var name in all)
4
- __defProp(target, name, { get: all[name], enumerable: true });
5
- };
6
-
7
- export {
8
- __export
9
- };
10
- //# sourceMappingURL=chunk-J5LGTIGS.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -1,45 +0,0 @@
1
- // src/meta.ts
2
- import { Plugin } from "@dxos/app-framework";
3
-
4
- // dx.config.ts
5
- import { Config2 } from "@dxos/app-framework/config";
6
- import { trim } from "@dxos/util";
7
- var dx_config_default = Config2.make({
8
- plugin: {
9
- key: "org.dxos.plugin.file",
10
- name: "File",
11
- author: "DXOS",
12
- description: trim`
13
- FilePlugin enables DXOS Composer to store and preview binary files — images, videos, and PDFs — as
14
- first-class ECHO objects. Uploaded bytes are routed through a pluggable backend system: the built-in
15
- inline backend serialises the file directly onto the ECHO document, while external backends (e.g. WNFS)
16
- can be contributed by other plugins.
17
-
18
- Accepted formats are images (jpg, jpeg, png, gif, webp, svg), videos (mp4, webm, mov), and PDFs,
19
- up to a 4 MB limit per file for the inline backend. The preview surface renders the appropriate HTML
20
- element for each MIME class and surfaces inside article, section, and slide roles.
21
-
22
- A UrlResolver capability lets external-storage backends convert opaque storage URIs into renderable
23
- blob, data, or HTTP URLs at view time, keeping the ECHO object schema backend-agnostic. A companion
24
- Markdown extension allows file objects to be embedded directly in Markdown documents.
25
-
26
- Backend selection is user-configurable in the plugin settings panel, which lists all registered
27
- backends with their descriptions. Selecting a backend persists the choice to the ECHO-backed settings
28
- atom so the preference is shared across devices.
29
- `,
30
- icon: {
31
- key: "ph--file--regular",
32
- hue: "teal"
33
- },
34
- source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-file",
35
- spec: "PLUGIN.mdl"
36
- }
37
- });
38
-
39
- // src/meta.ts
40
- var meta = Plugin.getMetaFromConfig(dx_config_default);
41
-
42
- export {
43
- meta
44
- };
45
- //# sourceMappingURL=chunk-LBZ4MCLI.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/meta.ts", "../../../dx.config.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\n\nimport config from '../dx.config';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n", "//\n// Copyright 2026 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.file',\n name: 'File',\n author: 'DXOS',\n description: trim`\n FilePlugin enables DXOS Composer to store and preview binary files — images, videos, and PDFs — as\n first-class ECHO objects. Uploaded bytes are routed through a pluggable backend system: the built-in\n inline backend serialises the file directly onto the ECHO document, while external backends (e.g. WNFS)\n can be contributed by other plugins.\n\n Accepted formats are images (jpg, jpeg, png, gif, webp, svg), videos (mp4, webm, mov), and PDFs,\n up to a 4 MB limit per file for the inline backend. The preview surface renders the appropriate HTML\n element for each MIME class and surfaces inside article, section, and slide roles.\n\n A UrlResolver capability lets external-storage backends convert opaque storage URIs into renderable\n blob, data, or HTTP URLs at view time, keeping the ECHO object schema backend-agnostic. A companion\n Markdown extension allows file objects to be embedded directly in Markdown documents.\n\n Backend selection is user-configurable in the plugin settings panel, which lists all registered\n backends with their descriptions. Selecting a backend persists the choice to the ECHO-backed settings\n atom so the preference is shared across devices.\n `,\n icon: { key: 'ph--file--regular', hue: 'teal' },\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-file',\n spec: 'PLUGIN.mdl',\n },\n});\n"],
5
- "mappings": ";AAIA,SAASA,cAAc;;;ACAvB,SAASC,eAAe;AACxB,SAASC,YAAY;AAErB,IAAA,oBAAeD,QAAQE,KAAK;EAC1BC,QAAQ;IACNC,KAAK;IACLC,MAAM;IACNC,QAAQ;IACRC,aAAaN;;;;;;;;;;;;;;;;;;IAkBbO,MAAM;MAAEJ,KAAK;MAAqBK,KAAK;IAAO;IAC9CC,QAAQ;IACRC,MAAM;EACR;AACF,CAAA;;;AD1BO,IAAMC,OAAOC,OAAOC,kBAAkBC,iBAAAA;",
6
- "names": ["Plugin", "Config2", "trim", "make", "plugin", "key", "name", "author", "description", "icon", "hue", "source", "spec", "meta", "Plugin", "getMetaFromConfig", "config"]
7
- }
@@ -1,136 +0,0 @@
1
- import {
2
- __export
3
- } from "./chunk-J5LGTIGS.mjs";
4
-
5
- // src/types/index.ts
6
- import { File as File3 } from "@dxos/types";
7
-
8
- // src/types/limits.ts
9
- var MAX_FILE_SIZE = 4 * 1024 * 1024;
10
- var ACCEPTED_MIME = {
11
- "image/*": [
12
- ".jpg",
13
- ".jpeg",
14
- ".png",
15
- ".gif",
16
- ".webp",
17
- ".svg"
18
- ],
19
- "video/*": [
20
- ".mp4",
21
- ".webm",
22
- ".mov"
23
- ],
24
- "application/pdf": [
25
- ".pdf"
26
- ]
27
- };
28
- var isAcceptedMimeType = (type) => {
29
- if (type === "application/pdf") {
30
- return true;
31
- }
32
- if (type.startsWith("image/") || type.startsWith("video/")) {
33
- return true;
34
- }
35
- return false;
36
- };
37
-
38
- // src/types/types.ts
39
- import * as Schema from "effect/Schema";
40
- import { meta } from "#meta";
41
- (function(FileAction2) {
42
- FileAction2.UploadAnnotationId = /* @__PURE__ */ Symbol.for(`${meta.profile.key}.annotation.upload`);
43
- FileAction2.CreateFileSchema = Schema.Struct({
44
- file: Schema.instanceOf(File).annotations({
45
- [FileAction2.UploadAnnotationId]: ACCEPTED_MIME
46
- })
47
- });
48
- })(FileAction || (FileAction = {}));
49
- var FileAction;
50
-
51
- // src/types/FileCapabilities.ts
52
- var FileCapabilities_exports = {};
53
- __export(FileCapabilities_exports, {
54
- Backend: () => Backend,
55
- SettingsAtom: () => SettingsAtom,
56
- UrlResolver: () => UrlResolver
57
- });
58
- import { Capability } from "@dxos/app-framework";
59
- import { meta as meta2 } from "#meta";
60
- var Backend = Capability.make(`${meta2.profile.key}.capability.backend`);
61
- var UrlResolver = Capability.make(`${meta2.profile.key}.capability.url-resolver`);
62
- var SettingsAtom = Capability.make(`${meta2.profile.key}.capability.settings`);
63
-
64
- // src/types/FileOperation.ts
65
- var FileOperation_exports = {};
66
- __export(FileOperation_exports, {
67
- Create: () => Create,
68
- Read: () => Read
69
- });
70
- import * as Schema2 from "effect/Schema";
71
- import { Capability as Capability2 } from "@dxos/app-framework";
72
- import { Operation } from "@dxos/compute";
73
- import { Database, DXN, Ref, Type } from "@dxos/echo";
74
- import { ContentBlock, File as File2 } from "@dxos/types";
75
- import { meta as meta3 } from "#meta";
76
- var makeKey = (name) => DXN.make(`${meta3.profile.key}.operation.${name}`);
77
- var Create = Operation.make({
78
- meta: {
79
- key: makeKey("create"),
80
- name: "Create File",
81
- icon: "ph--file--regular"
82
- },
83
- services: [
84
- Capability2.Service
85
- ],
86
- input: Schema2.extend(FileAction.CreateFileSchema, Schema2.Struct({
87
- db: Database.Database
88
- })),
89
- output: Schema2.Struct({
90
- object: Type.getSchema(File2.File)
91
- })
92
- });
93
- var Read = Operation.make({
94
- meta: {
95
- key: makeKey("read"),
96
- name: "Read File",
97
- 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).",
98
- icon: "ph--file-arrow-down--regular"
99
- },
100
- input: Schema2.Struct({
101
- file: Ref.Ref(File2.File).annotations({
102
- description: "The file to read."
103
- })
104
- }),
105
- output: ContentBlock.ContentBlockResult,
106
- services: [
107
- Database.Service
108
- ]
109
- });
110
-
111
- // src/types/Settings.ts
112
- var Settings_exports = {};
113
- __export(Settings_exports, {
114
- DEFAULT_BACKEND_ID: () => DEFAULT_BACKEND_ID,
115
- Settings: () => Settings
116
- });
117
- import * as Schema3 from "effect/Schema";
118
- var DEFAULT_BACKEND_ID = "inline";
119
- var Settings = Schema3.mutable(Schema3.Struct({
120
- backend: Schema3.optional(Schema3.String.annotations({
121
- title: "File storage backend",
122
- 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."
123
- }))
124
- }));
125
-
126
- export {
127
- MAX_FILE_SIZE,
128
- ACCEPTED_MIME,
129
- isAcceptedMimeType,
130
- FileAction,
131
- FileCapabilities_exports,
132
- FileOperation_exports,
133
- Settings_exports,
134
- File3 as File
135
- };
136
- //# sourceMappingURL=chunk-YODPX62X.mjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/types/index.ts", "../../../src/types/limits.ts", "../../../src/types/types.ts", "../../../src/types/FileCapabilities.ts", "../../../src/types/FileOperation.ts", "../../../src/types/Settings.ts"],
4
- "sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nexport { File } from '@dxos/types';\n\nexport * from './limits';\nexport * from './types';\n\nexport * as FileCapabilities from './FileCapabilities';\nexport * as FileOperation from './FileOperation';\nexport * as Settings from './Settings';\n", "//\n// Copyright 2026 DXOS.org\n//\n\nexport const MAX_FILE_SIZE = 4 * 1024 * 1024;\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", "//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { meta } from '#meta';\n\nimport { ACCEPTED_MIME } from './limits';\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", "//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport { type Atom } from '@effect-atom/atom-react';\n\nimport { Capability } from '@dxos/app-framework';\nimport { type Database } from '@dxos/echo';\nimport { type Space } from '@dxos/react-client/echo';\nimport { File } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nimport * as Settings from './Settings';\n\n/**\n * A file storage backend. Each backend ingests a File from the user and\n * returns the metadata + the {@link File.FileData} to attach to a\n * {@link File.File} object.\n */\nexport type Backend = {\n /** Stable backend id (e.g. 'inline', 'wnfs'). Used as the settings key. */\n readonly id: string;\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 /** Upload a file. Throws on validation errors (size cap, unsupported MIME). */\n readonly upload: (file: globalThis.File, db: Database.Database) => Promise<UploadResult>;\n};\n\nexport type UploadResult = {\n readonly name: string;\n readonly type: string;\n readonly size: number;\n readonly data: File.FileData;\n};\n\nexport const Backend = Capability.make<Backend>(`${meta.profile.key}.capability.backend`);\n\n/**\n * Resolves an external URL (e.g. `wnfs://…`) into a renderable URL (a\n * `blob:`, `data:`, or `http(s):` URL). Consumers iterate registered\n * resolvers and pick the first that returns true from {@link UrlResolver#test}.\n */\nexport type UrlResolver = {\n readonly id: string;\n readonly test: (url: string) => boolean;\n readonly resolve: (url: string, file: File.File, space?: Space) => Promise<string | undefined>;\n};\n\nexport const UrlResolver = Capability.make<UrlResolver>(`${meta.profile.key}.capability.url-resolver`);\n\nexport const SettingsAtom = Capability.make<Atom.Writable<Settings.Settings>>(\n `${meta.profile.key}.capability.settings`,\n);\n", "//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport { Capability } from '@dxos/app-framework';\nimport { Operation } from '@dxos/compute';\nimport { Database, DXN, Ref, Type } from '@dxos/echo';\nimport { ContentBlock, File } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nimport { FileAction } from './types';\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(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", "//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nexport const DEFAULT_BACKEND_ID = '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"],
5
- "mappings": ";;;;;AAIA,SAASA,QAAAA,aAAY;;;ACAd,IAAMC,gBAAgB,IAAI,OAAO;AAEjC,IAAMC,gBAA0C;EACrD,WAAW;IAAC;IAAQ;IAAS;IAAQ;IAAQ;IAAS;;EACtD,WAAW;IAAC;IAAQ;IAAS;;EAC7B,mBAAmB;IAAC;;AACtB;AAEO,IAAMC,qBAAqB,CAACC,SAAAA;AACjC,MAAIA,SAAS,mBAAmB;AAC9B,WAAO;EACT;AACA,MAAIA,KAAKC,WAAW,QAAA,KAAaD,KAAKC,WAAW,QAAA,GAAW;AAC1D,WAAO;EACT;AACA,SAAO;AACT;;;AChBA,YAAYC,YAAY;AAExB,SAASC,YAAY;UAIJC,aAAAA;cACFC,qBAAqBC,uBAAOC,IAAI,GAAGC,KAAKC,QAAQC,GAAG,oBAAoB;cAEvEC,mBAA0BC,cAAO;IAC5CC,MAAaC,kBAAWC,IAAAA,EAAMC,YAAY;MACxC,CAAAZ,YAACC,kBAAAA,GAAqBY;IACxB,CAAA;EACF,CAAA;AAGF,GAViBb,eAAAA,aAAAA,CAAAA,EAAAA;;;;ACVjB;;;;;;AAQA,SAASc,kBAAkB;AAK3B,SAASC,QAAAA,aAAY;AA2Bd,IAAMC,UAAUF,WAAWG,KAAc,GAAGF,MAAKG,QAAQC,GAAG,qBAAqB;AAajF,IAAMC,cAAcN,WAAWG,KAAkB,GAAGF,MAAKG,QAAQC,GAAG,0BAA0B;AAE9F,IAAME,eAAeP,WAAWG,KACrC,GAAGF,MAAKG,QAAQC,GAAG,sBAAsB;;;ACxD3C;;;;;AAMA,YAAYG,aAAY;AAExB,SAASC,cAAAA,mBAAkB;AAC3B,SAASC,iBAAiB;AAC1B,SAASC,UAAUC,KAAKC,KAAKC,YAAY;AACzC,SAASC,cAAcC,QAAAA,aAAY;AAEnC,SAASC,QAAAA,aAAY;AAIrB,IAAMC,UAAU,CAACC,SAAiBC,IAAIC,KAAK,GAAGC,MAAKC,QAAQC,GAAG,cAAcL,IAAAA,EAAM;AAE3E,IAAMM,SAASC,UAAUL,KAAK;EACnCC,MAAM;IAAEE,KAAKN,QAAQ,QAAA;IAAWC,MAAM;IAAeQ,MAAM;EAAoB;EAC/EC,UAAU;IAACC,YAAWC;;EACtBC,OAAcC,eAAOC,WAAWC,kBAAyBC,eAAO;IAAEC,IAAIC,SAASA;EAAS,CAAA,CAAA;EACxFC,QAAeH,eAAO;IACpBI,QAAQC,KAAKC,UAAUC,MAAKA,IAAI;EAClC,CAAA;AACF,CAAA;AAEO,IAAMC,OAAOjB,UAAUL,KAAK;EACjCC,MAAM;IACJE,KAAKN,QAAQ,MAAA;IACbC,MAAM;IACNyB,aACE;IACFjB,MAAM;EACR;EACAI,OAAcI,eAAO;IACnBU,MAAMC,IAAIA,IAAIJ,MAAKA,IAAI,EAAEK,YAAY;MACnCH,aAAa;IACf,CAAA;EACF,CAAA;EACAN,QAAQU,aAAaC;EACrBrB,UAAU;IAACS,SAASP;;AACtB,CAAA;;;AC3CA;;;;;AAMA,YAAYoB,aAAY;AAEjB,IAAMC,qBAAqB;AAE3B,IAAMC,WAAkBC,gBACtBC,eAAO;EACZC,SAAgBC,iBACPC,eAAOC,YAAY;IACxBC,OAAO;IACPC,aACE;EACJ,CAAA,CAAA;AAEJ,CAAA,CAAA;",
6
- "names": ["File", "MAX_FILE_SIZE", "ACCEPTED_MIME", "isAcceptedMimeType", "type", "startsWith", "Schema", "meta", "FileAction", "UploadAnnotationId", "Symbol", "for", "meta", "profile", "key", "CreateFileSchema", "Struct", "file", "instanceOf", "File", "annotations", "ACCEPTED_MIME", "Capability", "meta", "Backend", "make", "profile", "key", "UrlResolver", "SettingsAtom", "Schema", "Capability", "Operation", "Database", "DXN", "Ref", "Type", "ContentBlock", "File", "meta", "makeKey", "name", "DXN", "make", "meta", "profile", "key", "Create", "Operation", "icon", "services", "Capability", "Service", "input", "extend", "FileAction", "CreateFileSchema", "Struct", "db", "Database", "output", "object", "Type", "getSchema", "File", "Read", "description", "file", "Ref", "annotations", "ContentBlock", "ContentBlockResult", "Schema", "DEFAULT_BACKEND_ID", "Settings", "mutable", "Struct", "backend", "optional", "String", "annotations", "title", "description"]
7
- }