studiograph 1.3.48-next.223 → 1.3.48-next.224
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.
- package/dist/core/artifact-asset-resolution.d.ts +90 -0
- package/dist/core/artifact-asset-resolution.js +138 -0
- package/dist/core/artifact-asset-resolution.js.map +1 -0
- package/dist/core/artifact-asset-urls.d.ts +55 -9
- package/dist/core/artifact-asset-urls.js +69 -17
- package/dist/core/artifact-asset-urls.js.map +1 -1
- package/dist/core/artifact-export.d.ts +11 -5
- package/dist/core/artifact-export.js +14 -5
- package/dist/core/artifact-export.js.map +1 -1
- package/dist/core/embeds.d.ts +13 -1
- package/dist/core/embeds.js +36 -6
- package/dist/core/embeds.js.map +1 -1
- package/dist/mcp/tools.js +10 -2
- package/dist/mcp/tools.js.map +1 -1
- package/dist/server/artifact-asset-mint.d.ts +16 -1
- package/dist/server/artifact-asset-mint.js +28 -1
- package/dist/server/artifact-asset-mint.js.map +1 -1
- package/dist/server/index.js +4 -8
- package/dist/server/index.js.map +1 -1
- package/dist/server/middleware/sanitize.js +13 -0
- package/dist/server/middleware/sanitize.js.map +1 -1
- package/dist/server/routes/artifact-export-api.js +37 -29
- package/dist/server/routes/artifact-export-api.js.map +1 -1
- package/dist/server/routes/asset-api.d.ts +5 -0
- package/dist/server/routes/asset-api.js +12 -6
- package/dist/server/routes/asset-api.js.map +1 -1
- package/dist/server/routes/share-api.js +22 -3
- package/dist/server/routes/share-api.js.map +1 -1
- package/dist/services/artifact-render-export.js +7 -1
- package/dist/services/artifact-render-export.js.map +1 -1
- package/dist/services/assets/index.d.ts +2 -15
- package/dist/services/assets/index.js +6 -17
- package/dist/services/assets/index.js.map +1 -1
- package/dist/web/_app/immutable/chunks/{CUrld5SL.js → -t83DF7C.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BuiaLd292.js → 6nUT-VBB2.js} +1 -1
- package/dist/web/_app/immutable/chunks/AnhRkYV52.js +744 -0
- package/dist/web/_app/immutable/chunks/{rMl0XZu1.js → Ao_LrVH5.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BAssXoEd.js → B3VdagcJ.js} +1 -1
- package/dist/web/_app/immutable/chunks/{DYqmg_JJ.js → B4YZXO8l.js} +1 -1
- package/dist/web/_app/immutable/chunks/{WB474MZm2.js → B9Zuctc62.js} +1 -1
- package/dist/web/_app/immutable/chunks/{_ZG8RdIU.js → BC1gZs1g.js} +2 -2
- package/dist/web/_app/immutable/chunks/{BLzN3uN32.js → BGyDFWHN2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{CUCNoxpX.js → B_6yJ6so.js} +2 -2
- package/dist/web/_app/immutable/chunks/{yzwVqzGf2.js → Bcjp5rwL2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{CENYbZjU.js → BmW_6c_j.js} +2 -2
- package/dist/web/_app/immutable/chunks/{Dp9_M1oy.js → BpvVXmos.js} +1 -1
- package/dist/web/_app/immutable/chunks/{C4bv0Znc.js → Bwp7bXi4.js} +2 -2
- package/dist/web/_app/immutable/chunks/{CcgbOXLb2.js → C0RldARH2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{RmUKsH-5.js → C2qu9xZ8.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BC2jtez-2.js → C60DaMCS2.js} +1 -1
- package/dist/web/_app/immutable/chunks/CAXW8Nmb.js +1 -0
- package/dist/web/_app/immutable/chunks/{QyFwDNHb2.js → CCCeoxwK2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{qkSk13Tb.js → CIeBI0c2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{D_ld7ciX2.js → CIoGoHCo2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{35lQgzbP.js → CRIz5Q5Y.js} +1 -1
- package/dist/web/_app/immutable/chunks/{DeSyyZF6.js → CRZeh6Aj.js} +1 -1
- package/dist/web/_app/immutable/chunks/{B8kgG0Ag.js → CYSx3615.js} +2 -2
- package/dist/web/_app/immutable/chunks/{C_PkOSJS.js → CYZmxa1v.js} +1 -1
- package/dist/web/_app/immutable/chunks/{D4NCrNzW.js → CqbR59wF.js} +1 -1
- package/dist/web/_app/immutable/chunks/{_YtHSmce.js → Cu8Yu29c.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BrVKbPYj.js → Cx8pmbES.js} +1 -1
- package/dist/web/_app/immutable/chunks/{CmPmaBbY.js → CyNRUktj.js} +1 -1
- package/dist/web/_app/immutable/chunks/{C9lGIUiN2.js → CyV_OoCb2.js} +2 -2
- package/dist/web/_app/immutable/chunks/{D8GgdCFp.js → D2zMtlSH.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BTXsnPKE.js → D3QCJxhD.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BaBB9wCS.js → D6fp0owc.js} +1 -1
- package/dist/web/_app/immutable/chunks/{CM25NOAL.js → D7JE54es.js} +4 -4
- package/dist/web/_app/immutable/chunks/{HAFWjPbn.js → DDVF99oi.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BttmHvHm.js → DP4HDq8u.js} +1 -1
- package/dist/web/_app/immutable/chunks/{B-mo8ZxS.js → DP52fjuK.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BmUbjUm8.js → DQfSUzke.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BvbOW3CJ.js → De4OMlnM.js} +1 -1
- package/dist/web/_app/immutable/chunks/{DezF2bo6.js → Des3cNUX.js} +1 -1
- package/dist/web/_app/immutable/chunks/{CsxJTjzw.js → DgQSwBmD.js} +3 -3
- package/dist/web/_app/immutable/chunks/{CZ1TQAgs.js → DnllR84m.js} +1 -1
- package/dist/web/_app/immutable/chunks/{Cg5OeWBp.js → Dr6jP5T7.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BnAKrbpE2.js → DtUYoQ1C2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{HhSbxyh4.js → DxhUCvzs.js} +1 -1
- package/dist/web/_app/immutable/chunks/{Q3BrqbOa2.js → DxiUN_H42.js} +2 -2
- package/dist/web/_app/immutable/chunks/{DS-3jd9N2.js → EpMQuP5V2.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BGIRDYfa.js → EvJzUsDT.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BK-7E4rk2.js → Gu-9QCBv2.js} +2 -2
- package/dist/web/_app/immutable/chunks/{Dz4-8HLS2.js → H1wvLZc22.js} +1 -1
- package/dist/web/_app/immutable/chunks/{Bk6Ioc8S.js → P-0w9V10.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BcJLYsWy.js → WS2KSVvk.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BgERmm0o.js → YdYdarYa.js} +2 -2
- package/dist/web/_app/immutable/chunks/{Dq-X3Ryv.js → ZyHiTWax.js} +1 -1
- package/dist/web/_app/immutable/chunks/{Bp_C3Oia.js → aJskHW8y.js} +1 -1
- package/dist/web/_app/immutable/chunks/{BN1rvhRq.js → gVjCNnvK.js} +2 -2
- package/dist/web/_app/immutable/chunks/nGN6gxLh.js +1 -0
- package/dist/web/_app/immutable/chunks/{DZcO1w7n.js → na61wY4U.js} +1 -1
- package/dist/web/_app/immutable/chunks/{DgtqwKlb.js → sQxt31WE.js} +1 -1
- package/dist/web/_app/immutable/entry/{app.D9fvfQnP.js → app.BrpHXnwT.js} +2 -2
- package/dist/web/_app/immutable/entry/start.DVWkt_5a.js +1 -0
- package/dist/web/_app/immutable/nodes/{0.l4H-fw4i.js → 0.CaZHo2oo.js} +2 -2
- package/dist/web/_app/immutable/nodes/{1.DVJdo2rO.js → 1.Dd1c9Fzc.js} +1 -1
- package/dist/web/_app/immutable/nodes/{10.CvX_6z0G.js → 10.UWzc4sgv.js} +1 -1
- package/dist/web/_app/immutable/nodes/{11.D6yl4wJT.js → 11.DsEiPo6x.js} +1 -1
- package/dist/web/_app/immutable/nodes/{12.Bz9t-w7B.js → 12.BneTfSHj.js} +1 -1
- package/dist/web/_app/immutable/nodes/{13.D3eIA6Yw.js → 13.Bw2Wxv72.js} +1 -1
- package/dist/web/_app/immutable/nodes/{15.v0ZBBIMh.js → 15.BsQCxh_Z.js} +1 -1
- package/dist/web/_app/immutable/nodes/{17.Be2Yl4Jl.js → 17.B71Yc_A5.js} +1 -1
- package/dist/web/_app/immutable/nodes/{18.BPex_uFo.js → 18.D7ZAG75m.js} +2 -2
- package/dist/web/_app/immutable/nodes/{2.CFnX8roc.js → 2.BueSfHRp.js} +4 -4
- package/dist/web/_app/immutable/nodes/{3.BfdLX1kU.js → 3.BtNnz-DP.js} +3 -3
- package/dist/web/_app/immutable/nodes/{4.BfTE3fvQ.js → 4.C9sViMrB.js} +3 -3
- package/dist/web/_app/immutable/nodes/{5.DyhYEnay.js → 5.oVYn4bfO.js} +1 -1
- package/dist/web/_app/immutable/nodes/{6.IztVrni3.js → 6.lL4xWTJ6.js} +2 -2
- package/dist/web/_app/immutable/nodes/{7.0Wp4Fpz0.js → 7.BvOLoMFf.js} +1 -1
- package/dist/web/_app/immutable/nodes/{8.yTJXG0iN.js → 8.Doa8EcN2.js} +1 -1
- package/dist/web/_app/immutable/nodes/{9.BNE1R3sv.js → 9.Cs0BVC4D.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +13 -13
- package/package.json +1 -1
- package/dist/core/field-library.d.ts +0 -62
- package/dist/core/field-library.js +0 -129
- package/dist/core/field-library.js.map +0 -1
- package/dist/mcp/comment-virtual-entity.d.ts +0 -36
- package/dist/mcp/comment-virtual-entity.js +0 -71
- package/dist/mcp/comment-virtual-entity.js.map +0 -1
- package/dist/server/routes/field-library-api.d.ts +0 -28
- package/dist/server/routes/field-library-api.js +0 -126
- package/dist/server/routes/field-library-api.js.map +0 -1
- package/dist/services/asset-upload-service.d.ts +0 -56
- package/dist/services/asset-upload-service.js +0 -200
- package/dist/services/asset-upload-service.js.map +0 -1
- package/dist/web/_app/immutable/chunks/CMSN2fE9.js +0 -1
- package/dist/web/_app/immutable/chunks/CXuf7zt72.js +0 -744
- package/dist/web/_app/immutable/chunks/sR112fuP.js +0 -1
- package/dist/web/_app/immutable/entry/start.BRmX4Fvo.js +0 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The artifact asset-resolution contract.
|
|
3
|
+
*
|
|
4
|
+
* Every artifact render context resolves workspace-asset references in exactly
|
|
5
|
+
* ONE way, chosen once per render as an explicit `AssetResolution` value:
|
|
6
|
+
*
|
|
7
|
+
* token — in-app canvas / present + headless Playwright render (PNG/PDF/
|
|
8
|
+
* inspect). URLs stay `/api/assets/...` and carry the `?at=`
|
|
9
|
+
* capability token; CSP allowlists `<origin>/api/assets/` only.
|
|
10
|
+
* share — public share page. URLs are the token-scoped
|
|
11
|
+
* `/api/share/<token>/asset/...` surface; CSP allowlists exactly
|
|
12
|
+
* that token's path — never `/api/share/` broadly.
|
|
13
|
+
* relative — self-contained HTML export. Bundled refs become relative
|
|
14
|
+
* `./assets/...` paths; unbundled refs become labeled inline
|
|
15
|
+
* placeholders. CSP carries NO network sources, unconditionally
|
|
16
|
+
* (`file:` only, for opening from disk) — an exported file never
|
|
17
|
+
* phones home, and a copy hosted on an http origin cannot beacon
|
|
18
|
+
* same-origin either.
|
|
19
|
+
* none — no asset access (unsaved previews, tests).
|
|
20
|
+
*
|
|
21
|
+
* Both document builders (`buildArtifactSrcdoc` in the web runtime and
|
|
22
|
+
* `buildArtifactHtmlExport` in core) derive the URL rewrite AND the CSP from
|
|
23
|
+
* the SAME resolution value via `applyAssetResolution` / `artifactCsp`, so a
|
|
24
|
+
* context can never mix models — "URLs from one scheme, CSP from another"
|
|
25
|
+
* (the share-page broken-images class) is unrepresentable.
|
|
26
|
+
*
|
|
27
|
+
* Fail-closed: a malformed origin or share token yields NO network source and
|
|
28
|
+
* NO rewrite rather than a permissive or splicable CSP.
|
|
29
|
+
*/
|
|
30
|
+
export type AssetResolution = {
|
|
31
|
+
mode: 'token';
|
|
32
|
+
/** Artifact-asset capability token (`?at=`). Null while the mint is in
|
|
33
|
+
* flight — the CSP already allowlists `/api/assets/` so the rebuilt
|
|
34
|
+
* document with the token doesn't change policy, only URLs. */
|
|
35
|
+
token: string | null;
|
|
36
|
+
/** App origin the asset URLs resolve against (CSP sources need an
|
|
37
|
+
* absolute origin; the sandboxed iframe inherits the parent base URL). */
|
|
38
|
+
origin: string;
|
|
39
|
+
} | {
|
|
40
|
+
mode: 'share';
|
|
41
|
+
shareToken: string;
|
|
42
|
+
origin: string;
|
|
43
|
+
} | {
|
|
44
|
+
mode: 'relative';
|
|
45
|
+
/** Decoded `assetId/filename` identity keys actually written into the
|
|
46
|
+
* export bundle. Refs NOT in the set render as labeled placeholders —
|
|
47
|
+
* never absolutized back to the workspace. Omitted = relativize all
|
|
48
|
+
* (caller bundles every ref). */
|
|
49
|
+
bundledKeys?: Set<string>;
|
|
50
|
+
} | {
|
|
51
|
+
mode: 'none';
|
|
52
|
+
};
|
|
53
|
+
export declare function isValidShareToken(token: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* The network source expressions (if any) the resolution adds to the asset
|
|
56
|
+
* CSP directives (`img-src` / `media-src` / `font-src`).
|
|
57
|
+
*
|
|
58
|
+
* D4 invariants (pinned by tests):
|
|
59
|
+
* - token → `<origin>/api/assets/` and nothing else
|
|
60
|
+
* - share → `<origin>/api/share/<token>/asset/` (the exact token path)
|
|
61
|
+
* - relative → `file:` ONLY, so the bundled `./assets/...` files load when
|
|
62
|
+
* the export is opened from disk. Deliberately NOT `'self'`:
|
|
63
|
+
* on an http(s)-hosted copy, `'self'` would let artifact JS
|
|
64
|
+
* beacon same-origin via img/media/font loads — "no network,
|
|
65
|
+
* unconditionally" means a hosted export shows placeholders
|
|
66
|
+
* instead (codex P1). A hostable export would be its own
|
|
67
|
+
* explicit mode, not a widening of this one.
|
|
68
|
+
* - none → nothing
|
|
69
|
+
*/
|
|
70
|
+
export declare function artifactCspAssetSources(resolution: AssetResolution): string[];
|
|
71
|
+
/**
|
|
72
|
+
* The full iframe/document Content-Security-Policy for an artifact render.
|
|
73
|
+
* Single definition for BOTH builders (web srcdoc + core HTML export) so the
|
|
74
|
+
* policy can't drift between contexts. The asset directives are derived from
|
|
75
|
+
* the resolution; everything else is the fixed sandbox posture (inline + blob
|
|
76
|
+
* scripts allowed, no eval, no network, no frames/objects/forms).
|
|
77
|
+
*
|
|
78
|
+
* `allowBaseOrigin` — the Playwright render path injects `<base href>` so
|
|
79
|
+
* root-relative asset URLs resolve in a `setContent` document; `base-uri`
|
|
80
|
+
* must then allow exactly that origin (everything else keeps `'none'`).
|
|
81
|
+
*/
|
|
82
|
+
export declare function artifactCsp(resolution?: AssetResolution, opts?: {
|
|
83
|
+
allowBaseOrigin?: string;
|
|
84
|
+
}): string;
|
|
85
|
+
/**
|
|
86
|
+
* Rewrite every workspace-asset URL in a built document according to the
|
|
87
|
+
* resolution. This is the ONLY url-rewrite exit in both builders — the same
|
|
88
|
+
* value that produced the CSP produces the URLs.
|
|
89
|
+
*/
|
|
90
|
+
export declare function applyAssetResolution(html: string, resolution?: AssetResolution): string;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The artifact asset-resolution contract.
|
|
3
|
+
*
|
|
4
|
+
* Every artifact render context resolves workspace-asset references in exactly
|
|
5
|
+
* ONE way, chosen once per render as an explicit `AssetResolution` value:
|
|
6
|
+
*
|
|
7
|
+
* token — in-app canvas / present + headless Playwright render (PNG/PDF/
|
|
8
|
+
* inspect). URLs stay `/api/assets/...` and carry the `?at=`
|
|
9
|
+
* capability token; CSP allowlists `<origin>/api/assets/` only.
|
|
10
|
+
* share — public share page. URLs are the token-scoped
|
|
11
|
+
* `/api/share/<token>/asset/...` surface; CSP allowlists exactly
|
|
12
|
+
* that token's path — never `/api/share/` broadly.
|
|
13
|
+
* relative — self-contained HTML export. Bundled refs become relative
|
|
14
|
+
* `./assets/...` paths; unbundled refs become labeled inline
|
|
15
|
+
* placeholders. CSP carries NO network sources, unconditionally
|
|
16
|
+
* (`file:` only, for opening from disk) — an exported file never
|
|
17
|
+
* phones home, and a copy hosted on an http origin cannot beacon
|
|
18
|
+
* same-origin either.
|
|
19
|
+
* none — no asset access (unsaved previews, tests).
|
|
20
|
+
*
|
|
21
|
+
* Both document builders (`buildArtifactSrcdoc` in the web runtime and
|
|
22
|
+
* `buildArtifactHtmlExport` in core) derive the URL rewrite AND the CSP from
|
|
23
|
+
* the SAME resolution value via `applyAssetResolution` / `artifactCsp`, so a
|
|
24
|
+
* context can never mix models — "URLs from one scheme, CSP from another"
|
|
25
|
+
* (the share-page broken-images class) is unrepresentable.
|
|
26
|
+
*
|
|
27
|
+
* Fail-closed: a malformed origin or share token yields NO network source and
|
|
28
|
+
* NO rewrite rather than a permissive or splicable CSP.
|
|
29
|
+
*/
|
|
30
|
+
import { appendAssetToken, rewriteAssetsToRelative, rewriteAssetsToShare, } from './artifact-asset-urls.js';
|
|
31
|
+
/** Normalize + validate an origin for use as a CSP source / URL prefix.
|
|
32
|
+
* Returns the bare `scheme://host[:port]` origin, or null when the value
|
|
33
|
+
* isn't a plain http(s) origin (fail-closed: no CSP source). */
|
|
34
|
+
function safeOrigin(value) {
|
|
35
|
+
try {
|
|
36
|
+
const url = new URL(value);
|
|
37
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
38
|
+
return null;
|
|
39
|
+
return url.origin;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Share tokens are server-minted (`shr_` + base64url), so anything outside
|
|
46
|
+
* this charset is not a token — and must never be spliced into a CSP source
|
|
47
|
+
* or URL path (`;`/whitespace would terminate the directive; `/`/`..` would
|
|
48
|
+
* widen the path scope). */
|
|
49
|
+
const SHARE_TOKEN_RE = /^[A-Za-z0-9._-]+$/;
|
|
50
|
+
export function isValidShareToken(token) {
|
|
51
|
+
return token.length > 0 && SHARE_TOKEN_RE.test(token);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The network source expressions (if any) the resolution adds to the asset
|
|
55
|
+
* CSP directives (`img-src` / `media-src` / `font-src`).
|
|
56
|
+
*
|
|
57
|
+
* D4 invariants (pinned by tests):
|
|
58
|
+
* - token → `<origin>/api/assets/` and nothing else
|
|
59
|
+
* - share → `<origin>/api/share/<token>/asset/` (the exact token path)
|
|
60
|
+
* - relative → `file:` ONLY, so the bundled `./assets/...` files load when
|
|
61
|
+
* the export is opened from disk. Deliberately NOT `'self'`:
|
|
62
|
+
* on an http(s)-hosted copy, `'self'` would let artifact JS
|
|
63
|
+
* beacon same-origin via img/media/font loads — "no network,
|
|
64
|
+
* unconditionally" means a hosted export shows placeholders
|
|
65
|
+
* instead (codex P1). A hostable export would be its own
|
|
66
|
+
* explicit mode, not a widening of this one.
|
|
67
|
+
* - none → nothing
|
|
68
|
+
*/
|
|
69
|
+
export function artifactCspAssetSources(resolution) {
|
|
70
|
+
switch (resolution.mode) {
|
|
71
|
+
case 'token': {
|
|
72
|
+
const origin = safeOrigin(resolution.origin);
|
|
73
|
+
return origin ? [`${origin}/api/assets/`] : [];
|
|
74
|
+
}
|
|
75
|
+
case 'share': {
|
|
76
|
+
const origin = safeOrigin(resolution.origin);
|
|
77
|
+
if (!origin || !isValidShareToken(resolution.shareToken))
|
|
78
|
+
return [];
|
|
79
|
+
return [`${origin}/api/share/${resolution.shareToken}/asset/`];
|
|
80
|
+
}
|
|
81
|
+
case 'relative':
|
|
82
|
+
return ['file:'];
|
|
83
|
+
case 'none':
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The full iframe/document Content-Security-Policy for an artifact render.
|
|
89
|
+
* Single definition for BOTH builders (web srcdoc + core HTML export) so the
|
|
90
|
+
* policy can't drift between contexts. The asset directives are derived from
|
|
91
|
+
* the resolution; everything else is the fixed sandbox posture (inline + blob
|
|
92
|
+
* scripts allowed, no eval, no network, no frames/objects/forms).
|
|
93
|
+
*
|
|
94
|
+
* `allowBaseOrigin` — the Playwright render path injects `<base href>` so
|
|
95
|
+
* root-relative asset URLs resolve in a `setContent` document; `base-uri`
|
|
96
|
+
* must then allow exactly that origin (everything else keeps `'none'`).
|
|
97
|
+
*/
|
|
98
|
+
export function artifactCsp(resolution = { mode: 'none' }, opts = {}) {
|
|
99
|
+
const sources = artifactCspAssetSources(resolution);
|
|
100
|
+
const withAsset = (base) => (sources.length ? `${base} ${sources.join(' ')}` : base);
|
|
101
|
+
const baseOrigin = opts.allowBaseOrigin ? safeOrigin(opts.allowBaseOrigin) : null;
|
|
102
|
+
return [
|
|
103
|
+
"default-src 'none'",
|
|
104
|
+
baseOrigin ? `base-uri ${baseOrigin}` : "base-uri 'none'",
|
|
105
|
+
"connect-src 'none'",
|
|
106
|
+
withAsset('font-src data: blob:'),
|
|
107
|
+
"form-action 'none'",
|
|
108
|
+
"frame-src 'none'",
|
|
109
|
+
withAsset('img-src data: blob:'),
|
|
110
|
+
withAsset('media-src data: blob:'),
|
|
111
|
+
"object-src 'none'",
|
|
112
|
+
"script-src 'unsafe-inline' blob:",
|
|
113
|
+
"style-src 'unsafe-inline'",
|
|
114
|
+
].join('; ');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Rewrite every workspace-asset URL in a built document according to the
|
|
118
|
+
* resolution. This is the ONLY url-rewrite exit in both builders — the same
|
|
119
|
+
* value that produced the CSP produces the URLs.
|
|
120
|
+
*/
|
|
121
|
+
export function applyAssetResolution(html, resolution = { mode: 'none' }) {
|
|
122
|
+
switch (resolution.mode) {
|
|
123
|
+
case 'token':
|
|
124
|
+
return resolution.token ? appendAssetToken(html, resolution.token) : html;
|
|
125
|
+
case 'share':
|
|
126
|
+
// Fail-closed symmetry: an invalid token produced no CSP source above,
|
|
127
|
+
// so don't emit URLs either — the refs stay `/api/assets/...`, which the
|
|
128
|
+
// share CSP blocks (visible as missing images, never as a leak).
|
|
129
|
+
return isValidShareToken(resolution.shareToken)
|
|
130
|
+
? rewriteAssetsToShare(html, resolution.shareToken)
|
|
131
|
+
: html;
|
|
132
|
+
case 'relative':
|
|
133
|
+
return rewriteAssetsToRelative(html, './assets', { bundledKeys: resolution.bundledKeys });
|
|
134
|
+
case 'none':
|
|
135
|
+
return html;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=artifact-asset-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-asset-resolution.js","sourceRoot":"","sources":["../../src/core/artifact-asset-resolution.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
* `/api/assets/...` references, so they can't drift:
|
|
5
5
|
* - mint → enumerate the exact asset keys an artifact references (allowlist)
|
|
6
6
|
* - in-app srcdoc + headless PNG/PDF render → append the `?at=` capability token
|
|
7
|
-
* -
|
|
7
|
+
* - public share page → rewrite to `/api/share/<token>/asset/...` paths
|
|
8
|
+
* - HTML export → rewrite to relative `./assets/...` paths (placeholders for
|
|
9
|
+
* anything not bundled)
|
|
10
|
+
* Which rewrite applies is decided once per render by the `AssetResolution`
|
|
11
|
+
* contract (artifact-asset-resolution.ts), which derives the CSP from the
|
|
12
|
+
* same value.
|
|
8
13
|
*
|
|
9
14
|
* Matches BOTH forms that appear in bundles:
|
|
10
15
|
* - root-relative `/api/assets/<assetId>/<filename>`
|
|
@@ -28,6 +33,28 @@ export interface ArtifactAssetRef {
|
|
|
28
33
|
assetId: string;
|
|
29
34
|
filename: string;
|
|
30
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Decode a URL filename segment back to the RAW stored filename — the canonical
|
|
38
|
+
* IDENTITY used to match the asset index (`row.filename`), the capability-token
|
|
39
|
+
* allowlist (`artifactAssetKey`), and the decoded serve-route path param. The URL
|
|
40
|
+
* segment itself is percent-encoded by `encodeAssetFilename` (e.g. a screenshot
|
|
41
|
+
* `page(1).png` → `page%281%29.png`); everything that reasons about asset identity
|
|
42
|
+
* must use this decoded form, or it won't match the raw name the index/serve speak
|
|
43
|
+
* (which is exactly the encoded-vs-raw mismatch that left special-char images 404).
|
|
44
|
+
* URL emitters below keep the encoded segment. Falls back to the raw input on a
|
|
45
|
+
* malformed `%` sequence (never throws).
|
|
46
|
+
*/
|
|
47
|
+
export declare function decodeAssetFilenameSegment(segment: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Percent-encode a RAW stored filename into the URL segment form — the single
|
|
50
|
+
* inverse of {@link decodeAssetFilenameSegment} (encode on emit, decode on
|
|
51
|
+
* parse). `encodeURIComponent` alone is not enough: it leaves `!~*'()`
|
|
52
|
+
* unescaped, and `()` are exactly the delimiters `ASSET_URL_RE` rejects — so
|
|
53
|
+
* encode those too. Result chars ∈ `[A-Za-z0-9._-]` + `%XX`, which the
|
|
54
|
+
* matcher's filename class accepts; the serve route decodes the path param
|
|
55
|
+
* back to the raw stored filename, so the round-trip is exact.
|
|
56
|
+
*/
|
|
57
|
+
export declare function encodeAssetFilename(filename: string): string;
|
|
31
58
|
/** Every distinct asset referenced in the text, in first-seen order. `filename`
|
|
32
59
|
* and `key` are the DECODED (raw) identity — matchable against the asset index
|
|
33
60
|
* and token allowlist — not the percent-encoded URL segment. */
|
|
@@ -41,16 +68,35 @@ export declare function findArtifactAssetRefs(text: string): ArtifactAssetRef[];
|
|
|
41
68
|
*/
|
|
42
69
|
export declare function appendAssetToken(text: string, token: string): string;
|
|
43
70
|
/**
|
|
44
|
-
* Rewrite asset URLs
|
|
45
|
-
*
|
|
71
|
+
* Rewrite asset URLs to the public-share scheme:
|
|
72
|
+
* `/api/share/<shareToken>/asset/<assetId>/<filename>`. Used by the share-mode
|
|
73
|
+
* asset resolution so the document's URLs and its CSP allowlist come from the
|
|
74
|
+
* same token. The filename segment stays in its encoded URL form. Idempotent:
|
|
75
|
+
* the output no longer matches the `/api/assets/` grammar, and the server-side
|
|
76
|
+
* share read may have already rewritten the body — re-applying is a no-op.
|
|
77
|
+
* Legacy 3-segment URLs aren't matched and pass through unchanged.
|
|
78
|
+
*/
|
|
79
|
+
export declare function rewriteAssetsToShare(text: string, shareToken: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* A labeled inline placeholder for an asset the export could not bundle
|
|
82
|
+
* (exporter lacks access / blob missing): a neutral framed box carrying the
|
|
83
|
+
* filename, as a `data:image/svg+xml` URI so it renders wherever the original
|
|
84
|
+
* URL appeared (`<img src>`, `srcset`, CSS `url(...)`) under the export's
|
|
85
|
+
* no-network CSP. Every output char is `%XX`-escaped past encodeURIComponent's
|
|
86
|
+
* leftovers (`!~*'()`), so the URI never carries a quote/paren/comma that
|
|
87
|
+
* would terminate an attribute, CSS `url()`, or srcset candidate.
|
|
88
|
+
*/
|
|
89
|
+
export declare function assetPlaceholderDataUri(filename: string): string;
|
|
90
|
+
/**
|
|
91
|
+
* Rewrite asset URLs for the self-contained HTML export. Refs whose key is in
|
|
92
|
+
* `bundledKeys` (the assets actually written into the zip) become relative
|
|
46
93
|
* `./assets/<id>/<file>` (offline-resolvable); any OTHER `/api/assets/...` ref
|
|
47
|
-
* (
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* (
|
|
51
|
-
* through unchanged.
|
|
94
|
+
* (exporter lacks access / blob missing — not bundled) becomes an explicit
|
|
95
|
+
* labeled placeholder. NEVER absolutized back to the workspace: an exported
|
|
96
|
+
* file must not phone home, and its no-network CSP would block the load anyway
|
|
97
|
+
* (D11b). With no `bundledKeys` every ref is relativized (caller bundles all
|
|
98
|
+
* of them). Legacy 3-segment URLs aren't matched and pass through unchanged.
|
|
52
99
|
*/
|
|
53
100
|
export declare function rewriteAssetsToRelative(text: string, baseDir?: string, opts?: {
|
|
54
101
|
bundledKeys?: Set<string>;
|
|
55
|
-
origin?: string;
|
|
56
102
|
}): string;
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
* `/api/assets/...` references, so they can't drift:
|
|
5
5
|
* - mint → enumerate the exact asset keys an artifact references (allowlist)
|
|
6
6
|
* - in-app srcdoc + headless PNG/PDF render → append the `?at=` capability token
|
|
7
|
-
* -
|
|
7
|
+
* - public share page → rewrite to `/api/share/<token>/asset/...` paths
|
|
8
|
+
* - HTML export → rewrite to relative `./assets/...` paths (placeholders for
|
|
9
|
+
* anything not bundled)
|
|
10
|
+
* Which rewrite applies is decided once per render by the `AssetResolution`
|
|
11
|
+
* contract (artifact-asset-resolution.ts), which derives the CSP from the
|
|
12
|
+
* same value.
|
|
8
13
|
*
|
|
9
14
|
* Matches BOTH forms that appear in bundles:
|
|
10
15
|
* - root-relative `/api/assets/<assetId>/<filename>`
|
|
@@ -38,7 +43,7 @@ const ASSET_URL_RE = /(https?:\/\/[^\s"'()<>\/]+)?\/api\/assets\/([A-Za-z0-9._%-
|
|
|
38
43
|
* URL emitters below keep the encoded segment. Falls back to the raw input on a
|
|
39
44
|
* malformed `%` sequence (never throws).
|
|
40
45
|
*/
|
|
41
|
-
function decodeAssetFilenameSegment(segment) {
|
|
46
|
+
export function decodeAssetFilenameSegment(segment) {
|
|
42
47
|
try {
|
|
43
48
|
return decodeURIComponent(segment);
|
|
44
49
|
}
|
|
@@ -46,6 +51,18 @@ function decodeAssetFilenameSegment(segment) {
|
|
|
46
51
|
return segment;
|
|
47
52
|
}
|
|
48
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Percent-encode a RAW stored filename into the URL segment form — the single
|
|
56
|
+
* inverse of {@link decodeAssetFilenameSegment} (encode on emit, decode on
|
|
57
|
+
* parse). `encodeURIComponent` alone is not enough: it leaves `!~*'()`
|
|
58
|
+
* unescaped, and `()` are exactly the delimiters `ASSET_URL_RE` rejects — so
|
|
59
|
+
* encode those too. Result chars ∈ `[A-Za-z0-9._-]` + `%XX`, which the
|
|
60
|
+
* matcher's filename class accepts; the serve route decodes the path param
|
|
61
|
+
* back to the raw stored filename, so the round-trip is exact.
|
|
62
|
+
*/
|
|
63
|
+
export function encodeAssetFilename(filename) {
|
|
64
|
+
return encodeURIComponent(filename).replace(/[!~*'()]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
65
|
+
}
|
|
49
66
|
/** Every distinct asset referenced in the text, in first-seen order. `filename`
|
|
50
67
|
* and `key` are the DECODED (raw) identity — matchable against the asset index
|
|
51
68
|
* and token allowlist — not the percent-encoded URL segment. */
|
|
@@ -77,31 +94,66 @@ export function appendAssetToken(text, token) {
|
|
|
77
94
|
});
|
|
78
95
|
}
|
|
79
96
|
/**
|
|
80
|
-
* Rewrite asset URLs
|
|
81
|
-
*
|
|
97
|
+
* Rewrite asset URLs to the public-share scheme:
|
|
98
|
+
* `/api/share/<shareToken>/asset/<assetId>/<filename>`. Used by the share-mode
|
|
99
|
+
* asset resolution so the document's URLs and its CSP allowlist come from the
|
|
100
|
+
* same token. The filename segment stays in its encoded URL form. Idempotent:
|
|
101
|
+
* the output no longer matches the `/api/assets/` grammar, and the server-side
|
|
102
|
+
* share read may have already rewritten the body — re-applying is a no-op.
|
|
103
|
+
* Legacy 3-segment URLs aren't matched and pass through unchanged.
|
|
104
|
+
*/
|
|
105
|
+
export function rewriteAssetsToShare(text, shareToken) {
|
|
106
|
+
return text.replace(ASSET_URL_RE, (_full, _origin, assetId, filename) => `/api/share/${shareToken}/asset/${assetId}/${filename}`);
|
|
107
|
+
}
|
|
108
|
+
/** Escape text for embedding inside an SVG source string. */
|
|
109
|
+
function escapeXml(s) {
|
|
110
|
+
return s.replace(/[&<>"']/g, (c) => c === '&' ? '&' : c === '<' ? '<' : c === '>' ? '>' : c === '"' ? '"' : ''');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A labeled inline placeholder for an asset the export could not bundle
|
|
114
|
+
* (exporter lacks access / blob missing): a neutral framed box carrying the
|
|
115
|
+
* filename, as a `data:image/svg+xml` URI so it renders wherever the original
|
|
116
|
+
* URL appeared (`<img src>`, `srcset`, CSS `url(...)`) under the export's
|
|
117
|
+
* no-network CSP. Every output char is `%XX`-escaped past encodeURIComponent's
|
|
118
|
+
* leftovers (`!~*'()`), so the URI never carries a quote/paren/comma that
|
|
119
|
+
* would terminate an attribute, CSS `url()`, or srcset candidate.
|
|
120
|
+
*/
|
|
121
|
+
export function assetPlaceholderDataUri(filename) {
|
|
122
|
+
const label = filename.length > 48 ? `${filename.slice(0, 45)}…` : filename;
|
|
123
|
+
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="640" height="360" viewBox="0 0 640 360">' +
|
|
124
|
+
'<rect width="640" height="360" fill="#f4f4f4"/>' +
|
|
125
|
+
'<rect x="0.5" y="0.5" width="639" height="359" fill="none" stroke="#d0d0d0"/>' +
|
|
126
|
+
'<g fill="#8a8a8a" font-family="system-ui, -apple-system, sans-serif" text-anchor="middle">' +
|
|
127
|
+
'<text x="320" y="168" font-size="15">Image not included in export</text>' +
|
|
128
|
+
`<text x="320" y="196" font-size="13">${escapeXml(label)}</text>` +
|
|
129
|
+
'</g></svg>';
|
|
130
|
+
// encodeAssetFilename is the strict percent-encoder (encodeURIComponent +
|
|
131
|
+
// the `!~*'()` leftovers) — exactly the delimiter-free guarantee the URI
|
|
132
|
+
// needs, applied to the whole SVG payload.
|
|
133
|
+
return `data:image/svg+xml,${encodeAssetFilename(svg)}`;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Rewrite asset URLs for the self-contained HTML export. Refs whose key is in
|
|
137
|
+
* `bundledKeys` (the assets actually written into the zip) become relative
|
|
82
138
|
* `./assets/<id>/<file>` (offline-resolvable); any OTHER `/api/assets/...` ref
|
|
83
|
-
* (
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* (
|
|
87
|
-
* through unchanged.
|
|
139
|
+
* (exporter lacks access / blob missing — not bundled) becomes an explicit
|
|
140
|
+
* labeled placeholder. NEVER absolutized back to the workspace: an exported
|
|
141
|
+
* file must not phone home, and its no-network CSP would block the load anyway
|
|
142
|
+
* (D11b). With no `bundledKeys` every ref is relativized (caller bundles all
|
|
143
|
+
* of them). Legacy 3-segment URLs aren't matched and pass through unchanged.
|
|
88
144
|
*/
|
|
89
145
|
export function rewriteAssetsToRelative(text, baseDir = './assets', opts = {}) {
|
|
90
146
|
const prefix = baseDir.replace(/\/+$/, '');
|
|
91
|
-
|
|
92
|
-
return text.replace(ASSET_URL_RE, (full, origin, assetId, filename, query) => {
|
|
147
|
+
return text.replace(ASSET_URL_RE, (_full, _origin, assetId, filename) => {
|
|
93
148
|
// `bundledKeys` are DECODED identity keys (artifactAssetKey over the raw
|
|
94
149
|
// filename), so decode the URL segment to look them up; the rewritten URL
|
|
95
150
|
// itself keeps the encoded segment (the browser decodes it back to the
|
|
96
151
|
// raw on-disk path in the export zip).
|
|
97
|
-
|
|
152
|
+
const raw = decodeAssetFilenameSegment(filename);
|
|
153
|
+
if (!opts.bundledKeys || opts.bundledKeys.has(`${assetId}/${raw}`)) {
|
|
98
154
|
return `${prefix}/${assetId}/${filename}`;
|
|
99
155
|
}
|
|
100
|
-
|
|
101
|
-
return full; // already absolute → resolves online as-is
|
|
102
|
-
if (originPrefix)
|
|
103
|
-
return `${originPrefix}/api/assets/${assetId}/${filename}${query ?? ''}`;
|
|
104
|
-
return full;
|
|
156
|
+
return assetPlaceholderDataUri(raw);
|
|
105
157
|
});
|
|
106
158
|
}
|
|
107
159
|
//# sourceMappingURL=artifact-asset-urls.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-asset-urls.js","sourceRoot":"","sources":["../../src/core/artifact-asset-urls.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"artifact-asset-urls.js","sourceRoot":"","sources":["../../src/core/artifact-asset-urls.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ArtifactBundle, ArtifactLibraryKey } from './artifact-bundle.js';
|
|
2
|
+
import { type AssetResolution } from './artifact-asset-resolution.js';
|
|
2
3
|
/** The neutral gray the hosted app presents artifacts on. The web stage rule
|
|
3
4
|
* (.artifact-stage[data-view-mode='fullscreen'] in ArtifactEntityView.svelte)
|
|
4
5
|
* must use the same value — a source-sync test pins it. */
|
|
@@ -9,13 +10,18 @@ export type ArtifactLibrarySources = Partial<Record<ArtifactLibrarySourceKey, st
|
|
|
9
10
|
export declare function artifactExportFilename(bundle: Pick<ArtifactBundle, 'artifactId' | 'title'>, extension?: ArtifactExportExtension): string;
|
|
10
11
|
export interface ArtifactHtmlExportOptions {
|
|
11
12
|
context?: 'editor' | 'fullscreen' | 'export';
|
|
13
|
+
/** Base URL for the headless (Playwright) render path so root-relative
|
|
14
|
+
* `/api/assets/...` URLs resolve in a `setContent` document. The CSP's
|
|
15
|
+
* `base-uri` is widened to exactly this origin. Never set on the
|
|
16
|
+
* standalone HTML export — a downloaded file must not phone home. */
|
|
12
17
|
baseHref?: string;
|
|
13
18
|
includeRenderHostStyles?: boolean;
|
|
14
19
|
librarySources?: ArtifactLibrarySources;
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
+
/** How workspace-asset refs resolve in THIS render — drives both the URL
|
|
21
|
+
* rewrite and the document CSP from one value (see
|
|
22
|
+
* artifact-asset-resolution.ts). Headless PNG/PDF passes token mode; the
|
|
23
|
+
* self-contained HTML export passes relative mode. Defaults to none
|
|
24
|
+
* (no asset access). */
|
|
25
|
+
assets?: AssetResolution;
|
|
20
26
|
}
|
|
21
27
|
export declare function buildArtifactHtmlExport(bundle: ArtifactBundle, options?: ArtifactHtmlExportOptions): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { encodeBase64, escapeAttribute, escapeHtml, escapeScript, escapeStyle, } from './artifact-escape.js';
|
|
2
|
-
import {
|
|
2
|
+
import { applyAssetResolution, artifactCsp } from './artifact-asset-resolution.js';
|
|
3
3
|
import { frameStepperSelector, frameStepperVisibilityCss } from './artifact-frame-selectors.js';
|
|
4
4
|
/** The neutral gray the hosted app presents artifacts on. The web stage rule
|
|
5
5
|
* (.artifact-stage[data-view-mode='fullscreen'] in ArtifactEntityView.svelte)
|
|
@@ -255,8 +255,16 @@ function addAttributesToHtmlTag(html, attrs) {
|
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
257
|
function headAdditions(bundle, entry, options) {
|
|
258
|
+
// The CSP is derived from the SAME AssetResolution that rewrites the asset
|
|
259
|
+
// URLs (finalize step), so this document can't carry URLs from one asset
|
|
260
|
+
// model and a policy from another. `base-uri` opens to exactly the
|
|
261
|
+
// baseHref's origin when the headless render injects a <base> tag.
|
|
262
|
+
// Safe unescaped: every dynamic CSP part is validated upstream (origins are
|
|
263
|
+
// URL-parsed, share tokens charset-checked) — no quote can reach here.
|
|
264
|
+
const csp = artifactCsp(options.assets, { allowBaseOrigin: options.baseHref });
|
|
258
265
|
const additions = [
|
|
259
266
|
'<meta charset="utf-8">',
|
|
267
|
+
`<meta http-equiv="Content-Security-Policy" content="${csp}">`,
|
|
260
268
|
options.baseHref ? `<base href="${escapeAttribute(options.baseHref)}">` : '',
|
|
261
269
|
'<meta name="generator" content="Studiograph Artifact Canvas">',
|
|
262
270
|
/<title[\s>]/i.test(entry) ? '' : `<title>${escapeHtml(bundle.title)}</title>`,
|
|
@@ -524,10 +532,11 @@ ${printPagination}
|
|
|
524
532
|
</style>`;
|
|
525
533
|
}
|
|
526
534
|
export function buildArtifactHtmlExport(bundle, options = {}) {
|
|
527
|
-
//
|
|
528
|
-
//
|
|
529
|
-
//
|
|
530
|
-
|
|
535
|
+
// Resolve workspace-asset URLs per the render's AssetResolution at the
|
|
536
|
+
// single exit (token: append ?at= for the cookieless headless render;
|
|
537
|
+
// relative: ./assets paths + placeholders for the standalone export).
|
|
538
|
+
// The CSP in headAdditions derives from the same value.
|
|
539
|
+
const finalize = (html) => applyAssetResolution(html, options.assets);
|
|
531
540
|
const rawEntry = stripNetworkAssetTags(bundle.files[bundle.entrypoint] ?? '');
|
|
532
541
|
const deferred = requestedLibraries(bundle).length > 0 ? deferInlineScripts(rawEntry) : { html: rawEntry, scripts: [] };
|
|
533
542
|
const entry = deferred.html;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-export.js","sourceRoot":"","sources":["../../src/core/artifact-export.ts"],"names":[],"mappings":"AACA,OAAO,EACL,YAAY,EACZ,eAAe,EACf,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"artifact-export.js","sourceRoot":"","sources":["../../src/core/artifact-export.ts"],"names":[],"mappings":"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"}
|
package/dist/core/embeds.d.ts
CHANGED
|
@@ -41,7 +41,9 @@ export declare function assetEmbed(filename: string, url: string): string;
|
|
|
41
41
|
export declare function deriveAssetDisplayName(filename: string): string;
|
|
42
42
|
/**
|
|
43
43
|
* References present in `before` but absent from `after` — i.e. embeds a
|
|
44
|
-
* body rewrite would drop. Set semantics on the
|
|
44
|
+
* body rewrite would drop. Set semantics on the CANONICALIZED reference
|
|
45
|
+
* (decoded asset identity — see {@link canonicalAssetRef}); the returned
|
|
46
|
+
* strings are the original `before` refs so messages show what the body said.
|
|
45
47
|
*/
|
|
46
48
|
export declare function droppedAssetEmbeds(before: string, after: string): string[];
|
|
47
49
|
/**
|
|
@@ -69,6 +71,11 @@ export declare function extractLegacyAssetUrls(fileContent: string): LegacyAsset
|
|
|
69
71
|
* `![[transclusions]]` are left untouched. Used by the public share read to
|
|
70
72
|
* point embedded images at the token-scoped `/api/share/{token}/asset/...`
|
|
71
73
|
* surface without leaking the authed `/api/assets` URLs to guests.
|
|
74
|
+
*
|
|
75
|
+
* D5 identity contract: `filename` reaches the callback DECODED (the raw
|
|
76
|
+
* stored name). A callback that emits a URL must percent-encode the segment
|
|
77
|
+
* it splices (`encodeAssetFilename`) — emitting the raw name breaks markdown/
|
|
78
|
+
* HTML URL parsing on spaces and parens.
|
|
72
79
|
*/
|
|
73
80
|
export declare function rewriteImmutableAssetUrls(body: string, replace: (assetId: string, filename: string) => string): string;
|
|
74
81
|
/**
|
|
@@ -79,6 +86,11 @@ export declare function rewriteImmutableAssetUrls(body: string, replace: (assetI
|
|
|
79
86
|
* entry actually embeds — not every asset that merely shares its repo. Legacy
|
|
80
87
|
* three-segment URLs and `![[transclusions]]` are intentionally ignored, the
|
|
81
88
|
* same way the rewrite leaves them untouched.
|
|
89
|
+
*
|
|
90
|
+
* D5 identity contract: `filename` is the DECODED raw stored name, directly
|
|
91
|
+
* comparable to `assets.db.filename` and to a Fastify-decoded route param —
|
|
92
|
+
* comparing the encoded URL segment against either was the latent
|
|
93
|
+
* special-char 404 on public shares (share-api embedded-asset check).
|
|
82
94
|
*/
|
|
83
95
|
export declare function extractImmutableAssetRefs(body: string): Array<{
|
|
84
96
|
assetId: string;
|