canopycms 0.0.67 → 0.0.68-int.101
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/README.md +24 -17
- package/dist/ai/handler.js +8 -0
- package/dist/api/admin-branch-health.js +17 -20
- package/dist/api/admin.d.ts +30 -9
- package/dist/api/admin.js +32 -2
- package/dist/api/assets.js +84 -76
- package/dist/api/branch-create-window.d.ts +12 -0
- package/dist/api/branch-create-window.js +13 -0
- package/dist/api/branch-review.d.ts +3 -3
- package/dist/api/branch-review.js +14 -5
- package/dist/api/branch-status.d.ts +5 -5
- package/dist/api/branch-status.js +26 -6
- package/dist/api/branch-withdraw.d.ts +2 -2
- package/dist/api/branch-withdraw.js +7 -2
- package/dist/api/branch.d.ts +15 -2
- package/dist/api/branch.js +118 -92
- package/dist/api/client.d.ts +18 -6
- package/dist/api/client.js +79 -12
- package/dist/api/content.d.ts +6 -5
- package/dist/api/content.js +44 -41
- package/dist/api/entries.js +16 -15
- package/dist/api/github-sync.d.ts +19 -1
- package/dist/api/github-sync.js +57 -10
- package/dist/api/index.d.ts +1 -1
- package/dist/api/reference-options.js +1 -1
- package/dist/api/resolve-references.js +14 -40
- package/dist/api/settings-helpers.d.ts +1 -1
- package/dist/api/settings-helpers.js +1 -4
- package/dist/api/user.d.ts +3 -0
- package/dist/api/user.js +3 -0
- package/dist/assets/asset-url.d.ts +22 -16
- package/dist/assets/asset-url.js +42 -25
- package/dist/assets/factory.d.ts +5 -0
- package/dist/assets/factory.js +5 -0
- package/dist/assets/finalize.js +3 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/assets/materialize.d.ts +153 -0
- package/dist/assets/materialize.js +402 -0
- package/dist/assets/store-local.d.ts +19 -5
- package/dist/assets/store-local.js +69 -10
- package/dist/assets/store-s3.d.ts +38 -7
- package/dist/assets/store-s3.js +128 -22
- package/dist/assets/transform-directives.d.ts +52 -13
- package/dist/assets/transform-directives.js +87 -27
- package/dist/assets/transform.d.ts +3 -3
- package/dist/assets/transform.js +13 -8
- package/dist/assets/types.d.ts +31 -4
- package/dist/auth/file-based-auth-cache.js +7 -8
- package/dist/authorization/content.d.ts +5 -4
- package/dist/authorization/content.js +5 -5
- package/dist/authorization/path.d.ts +11 -6
- package/dist/authorization/path.js +11 -6
- package/dist/authorization/types.d.ts +2 -2
- package/dist/branch-health.d.ts +7 -1
- package/dist/branch-health.js +8 -3
- package/dist/branch-metadata.d.ts +5 -5
- package/dist/branch-metadata.js +44 -36
- package/dist/branch-provisioning.d.ts +167 -0
- package/dist/branch-provisioning.js +501 -0
- package/dist/branch-schema-cache.d.ts +5 -3
- package/dist/branch-schema-cache.js +29 -11
- package/dist/branch-sparse.d.ts +23 -0
- package/dist/branch-sparse.js +118 -0
- package/dist/branch-workspace.d.ts +42 -3
- package/dist/branch-workspace.js +240 -94
- package/dist/build/asset-refs.d.ts +93 -0
- package/dist/build/asset-refs.js +251 -0
- package/dist/build-identity.d.ts +3 -0
- package/dist/build-identity.js +13 -0
- package/dist/cli/asset-refs.d.ts +52 -0
- package/dist/cli/asset-refs.js +194 -0
- package/dist/cli/cli.d.ts +15 -1
- package/dist/cli/cli.js +5928 -2195
- package/dist/cli/configured-asset-store.d.ts +12 -0
- package/dist/cli/configured-asset-store.js +46 -0
- package/dist/cli/generate-ai-content.js +2185 -587
- package/dist/cli/github-app-manifest.d.ts +4 -3
- package/dist/cli/github-app-manifest.js +4 -3
- package/dist/cli/init.js +30 -27
- package/dist/cli/migrate.js +12 -8
- package/dist/cli/sync.js +83 -37
- package/dist/cli/template-files/Dockerfile.cms.template +8 -0
- package/dist/cli/template-files/cdk-app.ts.template +4 -0
- package/dist/cli/template-files/cms-stack.ts.template +23 -12
- package/dist/cli/template-files/deploy-cms.yml.template +2 -0
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/config/helpers.js +1 -2
- package/dist/config/schemas/config.d.ts +19 -32
- package/dist/config/schemas/config.js +9 -11
- package/dist/config/schemas/field.js +1 -0
- package/dist/config/schemas/media.d.ts +4 -13
- package/dist/config/schemas/media.js +5 -8
- package/dist/config/schemas/url.d.ts +4 -20
- package/dist/config/schemas/url.js +6 -22
- package/dist/config/types.d.ts +30 -20
- package/dist/config/validation.d.ts +6 -0
- package/dist/config/validation.js +37 -0
- package/dist/content-listing.d.ts +12 -12
- package/dist/content-listing.js +10 -6
- package/dist/content-reader.d.ts +11 -2
- package/dist/content-reader.js +22 -14
- package/dist/content-store.d.ts +37 -9
- package/dist/content-store.js +70 -43
- package/dist/content-tree.d.ts +1 -1
- package/dist/content-tree.js +2 -2
- package/dist/context.d.ts +27 -9
- package/dist/context.js +154 -70
- package/dist/editor/BranchManager.d.ts +7 -1
- package/dist/editor/BranchManager.js +29 -14
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +2 -6
- package/dist/editor/Editor.d.ts +4 -3
- package/dist/editor/Editor.js +32 -22
- package/dist/editor/FormRenderer.js +34 -18
- package/dist/editor/PreviewFrame.d.ts +24 -0
- package/dist/editor/PreviewFrame.js +140 -0
- package/dist/editor/admin/SystemHealthPanel.js +47 -7
- package/dist/editor/components/BranchesDrawer.d.ts +9 -0
- package/dist/editor/components/BranchesDrawer.js +4 -0
- package/dist/editor/components/NoEditPermissionNotice.d.ts +10 -0
- package/dist/editor/components/NoEditPermissionNotice.js +17 -0
- package/dist/editor/context/AssetContext.d.ts +18 -35
- package/dist/editor/context/AssetContext.js +20 -29
- package/dist/editor/context/index.d.ts +1 -1
- package/dist/editor/context/index.js +1 -1
- package/dist/editor/editor-config.d.ts +1 -2
- package/dist/editor/editor-config.js +0 -23
- package/dist/editor/editor-utils.d.ts +24 -21
- package/dist/editor/editor-utils.js +75 -62
- package/dist/editor/fields/BlockField.d.ts +1 -0
- package/dist/editor/fields/BlockField.js +6 -4
- package/dist/editor/fields/CodeField.d.ts +1 -0
- package/dist/editor/fields/CodeField.js +2 -2
- package/dist/editor/fields/DateTimeField.d.ts +1 -0
- package/dist/editor/fields/DateTimeField.js +2 -2
- package/dist/editor/fields/FieldDescription.d.ts +16 -0
- package/dist/editor/fields/FieldDescription.js +11 -0
- package/dist/editor/fields/ImageField.d.ts +1 -0
- package/dist/editor/fields/ImageField.js +3 -2
- package/dist/editor/fields/InlineGroupField.js +4 -1
- package/dist/editor/fields/MarkdownField.d.ts +1 -0
- package/dist/editor/fields/MarkdownField.js +115 -20
- package/dist/editor/fields/NumberField.d.ts +1 -0
- package/dist/editor/fields/NumberField.js +2 -2
- package/dist/editor/fields/NumberListField.d.ts +1 -0
- package/dist/editor/fields/NumberListField.js +2 -2
- package/dist/editor/fields/ObjectField.d.ts +1 -0
- package/dist/editor/fields/ObjectField.js +5 -2
- package/dist/editor/fields/ReferenceField.d.ts +1 -0
- package/dist/editor/fields/ReferenceField.js +5 -4
- package/dist/editor/fields/SelectField.d.ts +1 -0
- package/dist/editor/fields/SelectField.js +2 -2
- package/dist/editor/fields/StringListField.d.ts +1 -0
- package/dist/editor/fields/StringListField.js +2 -2
- package/dist/editor/fields/TextField.d.ts +1 -0
- package/dist/editor/fields/TextField.js +2 -2
- package/dist/editor/fields/ToggleField.d.ts +1 -0
- package/dist/editor/fields/ToggleField.js +7 -4
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +3 -2
- package/dist/editor/fields/mdx-jsx-support.d.ts +1 -0
- package/dist/editor/fields/mdx-jsx-support.js +137 -0
- package/dist/editor/hooks/create-branch-request.d.ts +20 -0
- package/dist/editor/hooks/create-branch-request.js +52 -0
- package/dist/editor/hooks/useBranchActions.d.ts +13 -2
- package/dist/editor/hooks/useBranchActions.js +48 -17
- package/dist/editor/hooks/useBranchManager.d.ts +21 -0
- package/dist/editor/hooks/useBranchManager.js +204 -37
- package/dist/editor/hooks/useBranchesData.d.ts +6 -0
- package/dist/editor/hooks/useBranchesData.js +9 -3
- package/dist/editor/hooks/useCommentSystem.js +25 -6
- package/dist/editor/hooks/useDraftManager.d.ts +16 -1
- package/dist/editor/hooks/useDraftManager.js +193 -36
- package/dist/editor/hooks/useEntriesData.js +3 -3
- package/dist/editor/hooks/useEntryManager.d.ts +2 -1
- package/dist/editor/hooks/useEntryManager.js +34 -19
- package/dist/editor/media/AssetCard.d.ts +1 -1
- package/dist/editor/media/crop-math.d.ts +3 -4
- package/dist/editor/media/crop-math.js +11 -22
- package/dist/editor/media/editor-image-src.d.ts +7 -0
- package/dist/editor/media/editor-image-src.js +12 -0
- package/dist/editor/preview-asset-base.d.ts +8 -0
- package/dist/editor/preview-asset-base.js +13 -0
- package/dist/editor/preview-bridge.d.ts +9 -21
- package/dist/editor/preview-bridge.js +19 -139
- package/dist/editor/preview-path.d.ts +10 -0
- package/dist/editor/preview-path.js +20 -0
- package/dist/editor/theme.js +2 -2
- package/dist/entry-schema-registry.d.ts +4 -4
- package/dist/entry-schema-registry.js +10 -6
- package/dist/entry-schema.d.ts +27 -4
- package/dist/entry-schema.js +20 -3
- package/dist/git-manager.d.ts +173 -6
- package/dist/git-manager.js +594 -76
- package/dist/github-service.d.ts +15 -0
- package/dist/github-service.js +19 -1
- package/dist/http/handler.js +37 -13
- package/dist/http/index.d.ts +2 -0
- package/dist/http/index.js +2 -0
- package/dist/http/router.d.ts +2 -0
- package/dist/http/router.js +2 -1
- package/dist/http/types.d.ts +2 -0
- package/dist/http/worker-not-ready.d.ts +10 -0
- package/dist/http/worker-not-ready.js +24 -0
- package/dist/operating-mode/client-unsafe-strategy.js +0 -6
- package/dist/operating-mode/types.d.ts +1 -4
- package/dist/paths/branch-name.d.ts +5 -0
- package/dist/paths/branch-name.js +9 -0
- package/dist/paths/branch.d.ts +6 -2
- package/dist/paths/branch.js +16 -10
- package/dist/paths/index.d.ts +3 -3
- package/dist/paths/index.js +3 -3
- package/dist/paths/normalize.d.ts +7 -0
- package/dist/paths/normalize.js +9 -0
- package/dist/paths/validation.js +0 -2
- package/dist/preview.d.ts +8 -0
- package/dist/preview.js +7 -0
- package/dist/reference-resolver.d.ts +5 -21
- package/dist/reference-resolver.js +9 -44
- package/dist/resolve-canopy-user.js +2 -1
- package/dist/schema/schema-store.d.ts +54 -31
- package/dist/schema/schema-store.js +77 -31
- package/dist/server.d.ts +64 -9
- package/dist/server.js +48 -8
- package/dist/services.d.ts +18 -6
- package/dist/services.js +85 -70
- package/dist/settings-workspace.d.ts +23 -3
- package/dist/settings-workspace.js +197 -45
- package/dist/static/seo.d.ts +2 -14
- package/dist/static/seo.js +2 -25
- package/dist/submission-attribution.d.ts +73 -0
- package/dist/submission-attribution.js +221 -0
- package/dist/sync-core.d.ts +12 -1
- package/dist/sync-core.js +31 -13
- package/dist/task-queue/worker-status.d.ts +8 -0
- package/dist/task-queue/worker-status.js +17 -0
- package/dist/types.d.ts +31 -2
- package/dist/utils/content-serialize.d.ts +5 -2
- package/dist/utils/content-serialize.js +98 -24
- package/dist/utils/content-write-lock.d.ts +18 -7
- package/dist/utils/content-write-lock.js +18 -9
- package/dist/utils/debug.d.ts +8 -0
- package/dist/utils/debug.js +10 -2
- package/dist/utils/git.d.ts +32 -0
- package/dist/utils/git.js +42 -0
- package/dist/utils/occ-json-write.js +10 -2
- package/dist/utils/provision-log.d.ts +25 -0
- package/dist/utils/provision-log.js +49 -0
- package/dist/utils/provisioning-lock.d.ts +35 -5
- package/dist/utils/provisioning-lock.js +73 -12
- package/dist/utils/request-timing.d.ts +25 -0
- package/dist/utils/request-timing.js +101 -0
- package/dist/utils/sanitize-href.d.ts +8 -22
- package/dist/utils/sanitize-href.js +11 -28
- package/dist/utils/url-prefix.d.ts +30 -0
- package/dist/utils/url-prefix.js +61 -0
- package/dist/utils/yaml-source-splice.d.ts +58 -0
- package/dist/utils/yaml-source-splice.js +515 -0
- package/dist/validation/entry-validator.js +9 -3
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/worker/canopy-state.d.ts +45 -0
- package/dist/worker/canopy-state.js +75 -0
- package/dist/worker/cms-worker.d.ts +8 -3
- package/dist/worker/cms-worker.js +38 -2
- package/dist/worker/git-sync.d.ts +30 -12
- package/dist/worker/git-sync.js +253 -58
- package/dist/worker/history-rewrite.d.ts +1 -1
- package/dist/worker/history-rewrite.js +1 -1
- package/dist/worker/provisioned-workspace.d.ts +35 -0
- package/dist/worker/provisioned-workspace.js +50 -0
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +95 -23
- package/dist/worker/remote-git-maintenance.d.ts +3 -0
- package/dist/worker/remote-git-maintenance.js +11 -0
- package/dist/worker/sparse-cone.d.ts +20 -0
- package/dist/worker/sparse-cone.js +132 -0
- package/dist/worker/task-runner.js +99 -14
- package/dist/worker/worker-context.d.ts +6 -1
- package/package.json +8 -2
|
@@ -70,7 +70,7 @@ const getReferenceOptionsHandler = async (gc, ctx, req, _params) => {
|
|
|
70
70
|
// for an option the caller isn't allowed to see.
|
|
71
71
|
const checkAccess = await ctx.services.createContentAccessChecker(branchContext, branchContext.branchRoot, req.user);
|
|
72
72
|
const resolver = new ReferenceResolver(store, idIndex);
|
|
73
|
-
const options = await resolver.loadReferenceOptions(collections, displayField, search, entryTypes, (
|
|
73
|
+
const options = await resolver.loadReferenceOptions(collections, displayField, search, entryTypes, (logicalPath) => checkAccess(logicalPath, 'read').allowed);
|
|
74
74
|
return {
|
|
75
75
|
ok: true,
|
|
76
76
|
status: 200,
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { ContentStore } from '../content-store.js';
|
|
3
3
|
import { defineEndpoint } from './route-builder.js';
|
|
4
|
-
import { ReferenceResolver } from '../reference-resolver.js';
|
|
5
|
-
import { buildResolvedReference } from '../entry-schema.js';
|
|
6
|
-
import { computeEntryUrl } from '../utils/entry-url.js';
|
|
7
4
|
import { branchNameSchema, contentIdSchema } from './validators.js';
|
|
8
5
|
/**
|
|
9
6
|
* Resolution does sequential per-ID file I/O, so the request body caps how much filesystem work
|
|
@@ -20,49 +17,25 @@ const resolveReferencesBodySchema = z.object({
|
|
|
20
17
|
const resolveReferencesHandler = async (gc, ctx, req, params, body) => {
|
|
21
18
|
const { branchContext } = gc;
|
|
22
19
|
const { ids } = body;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const store = new ContentStore(branchContext.branchRoot, flatSchema, {
|
|
26
|
-
contentRootName,
|
|
20
|
+
const store = new ContentStore(branchContext.branchRoot, branchContext.flatSchema, {
|
|
21
|
+
contentRootName: ctx.services.config.contentRoot || 'content',
|
|
27
22
|
});
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
// Resolve each ID to full document
|
|
31
|
-
const resolver = new ReferenceResolver(store, idIndex);
|
|
32
|
-
// Build the access checker once, reused for every id instead of re-loading per id in the loop.
|
|
33
|
-
// A failure here (e.g. settings workspace unavailable) surfaces as a handler error, not
|
|
34
|
-
// swallowed silently per id.
|
|
23
|
+
// Built once for every id. A failure here (e.g. settings workspace unavailable) surfaces as a
|
|
24
|
+
// handler error rather than being swallowed per id.
|
|
35
25
|
const checkAccess = await ctx.services.createContentAccessChecker(branchContext, branchContext.branchRoot, req.user);
|
|
26
|
+
const access = (logicalPath) => checkAccess(logicalPath, 'read').allowed;
|
|
27
|
+
// The resolution `read()` applies to a reference field, so live preview shows this user what
|
|
28
|
+
// `read()` would: the target's data, or a `RestrictedReference` for a target they may not
|
|
29
|
+
// read. The target's own references stay ids, as in `read()`.
|
|
36
30
|
const resolved = {};
|
|
37
31
|
for (const id of ids) {
|
|
38
32
|
try {
|
|
39
|
-
const
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
const resolvedPath = await store.resolveDocumentPath(result.collection, result.slug);
|
|
43
|
-
const access = checkAccess(resolvedPath.relativePath, 'read');
|
|
44
|
-
if (!access.allowed)
|
|
45
|
-
continue;
|
|
46
|
-
// `resolveReferences: false` matches the server-side resolver (content-store.ts's
|
|
47
|
-
// resolveSingleReferenceOnce), so a nested reference inside a target renders the same way
|
|
48
|
-
// in live preview as on the published site, instead of resolving one level deeper.
|
|
49
|
-
const doc = await store.read(result.collection, result.slug, { resolveReferences: false });
|
|
50
|
-
if (doc && doc.data) {
|
|
51
|
-
// Same shape as the server-side resolver: target data first, then the reserved keys.
|
|
52
|
-
// Order is the corruption guard (a target modelling `id` as content must not shadow the
|
|
53
|
-
// real content ID); the extra keys (incl. `urlPath`) keep live preview and production
|
|
54
|
-
// in sync for consumers like client-reference-resolver.ts.
|
|
55
|
-
resolved[id] = buildResolvedReference(doc.data, {
|
|
56
|
-
id,
|
|
57
|
-
slug: result.slug,
|
|
58
|
-
collection: result.collection,
|
|
59
|
-
urlPath: computeEntryUrl(result.collection, result.slug, contentRootName),
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
33
|
+
const value = await store.resolveReferenceTarget(id, access);
|
|
34
|
+
if (value)
|
|
35
|
+
resolved[id] = value;
|
|
63
36
|
}
|
|
64
37
|
catch (error) {
|
|
65
|
-
//
|
|
38
|
+
// An id that fails to resolve is omitted rather than failing the whole request.
|
|
66
39
|
console.error(`Failed to resolve reference ID ${id}:`, error);
|
|
67
40
|
}
|
|
68
41
|
}
|
|
@@ -73,7 +46,8 @@ const resolveReferencesHandler = async (gc, ctx, req, params, body) => {
|
|
|
73
46
|
};
|
|
74
47
|
};
|
|
75
48
|
/**
|
|
76
|
-
* Resolve reference IDs
|
|
49
|
+
* Resolve reference IDs as a reference field would: full target data, or title + URL tagged
|
|
50
|
+
* `unavailable` for a target the user may not read. An id naming no entry is omitted.
|
|
77
51
|
* POST /:branch/resolve-references
|
|
78
52
|
* Body: { ids: string[] }
|
|
79
53
|
*/
|
|
@@ -30,7 +30,7 @@ export interface CommitSettingsResult {
|
|
|
30
30
|
/**
|
|
31
31
|
* Commit and push settings changes based on the mode.
|
|
32
32
|
* Both prod and dev use commitToSettingsBranch.
|
|
33
|
-
*
|
|
33
|
+
* Settings changes are never reviewed through a PR (see commitToSettingsBranch).
|
|
34
34
|
*/
|
|
35
35
|
export declare function commitSettings(ctx: ApiContext, options: {
|
|
36
36
|
context: {
|
|
@@ -23,7 +23,7 @@ export async function getSettingsBranchContext(ctx) {
|
|
|
23
23
|
/**
|
|
24
24
|
* Commit and push settings changes based on the mode.
|
|
25
25
|
* Both prod and dev use commitToSettingsBranch.
|
|
26
|
-
*
|
|
26
|
+
* Settings changes are never reviewed through a PR (see commitToSettingsBranch).
|
|
27
27
|
*/
|
|
28
28
|
export async function commitSettings(ctx, options) {
|
|
29
29
|
const strategy = operatingStrategy(options.mode);
|
|
@@ -38,9 +38,6 @@ export async function commitSettings(ctx, options) {
|
|
|
38
38
|
branchRoot: options.branchRoot,
|
|
39
39
|
files: options.fileName,
|
|
40
40
|
message: options.message,
|
|
41
|
-
createPR: strategy.shouldCreateSettingsPR({
|
|
42
|
-
autoCreateSettingsPR: ctx.services.config.autoCreateSettingsPR,
|
|
43
|
-
}),
|
|
44
41
|
});
|
|
45
42
|
if (!result.pushed) {
|
|
46
43
|
console.warn(`${options.message} committed but not pushed:`, result.error);
|
package/dist/api/user.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ApiResponse } from './types.js';
|
|
2
|
+
import type { BuildIdentity } from '../types.js';
|
|
2
3
|
export type UserInfoResponse = ApiResponse<{
|
|
3
4
|
userId: string;
|
|
4
5
|
groups: string[];
|
|
6
|
+
/** Admins only: the deployed version is reconnaissance for anyone else. */
|
|
7
|
+
build?: BuildIdentity;
|
|
5
8
|
}>;
|
|
6
9
|
export declare const USER_ROUTES: {
|
|
7
10
|
readonly whoami: import("./route-builder.js").RouteDefinition<undefined, undefined, UserInfoResponse>;
|
package/dist/api/user.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { defineEndpoint } from './route-builder.js';
|
|
2
|
+
import { isAdmin } from '../authorization/helpers.js';
|
|
3
|
+
import { getBuildIdentity } from '../build-identity.js';
|
|
2
4
|
/**
|
|
3
5
|
* This is a PUBLIC endpoint - no special permissions required
|
|
4
6
|
*/
|
|
@@ -10,6 +12,7 @@ const getUserInfoHandler = async (ctx, req) => {
|
|
|
10
12
|
data: {
|
|
11
13
|
userId: req.user.userId,
|
|
12
14
|
groups: req.user.groups,
|
|
15
|
+
...(isAdmin(req.user.groups) ? { build: getBuildIdentity() } : {}),
|
|
13
16
|
},
|
|
14
17
|
};
|
|
15
18
|
};
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Build/adjust transform URLs for `<img>`/srcset without pulling in the
|
|
3
|
-
* server-only transform engine. Isomorphic -
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* import from client (editor) code as well as during static builds.
|
|
3
|
+
* server-only transform engine. Isomorphic - none of its imports reach a node
|
|
4
|
+
* builtin, so this is safe to import from client (editor) code as well as during
|
|
5
|
+
* static builds.
|
|
7
6
|
*/
|
|
8
7
|
import { type CropRect, type OutputFormat } from './transform-directives.js';
|
|
9
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* The minimal shape `assetUrl`/`assetSrcSet` need from a stored asset reference. An
|
|
10
|
+
* `ImageFieldValue` is one, so passing a field value renders the crop the editor stored.
|
|
11
|
+
*/
|
|
10
12
|
export interface AssetRef {
|
|
11
13
|
src: string;
|
|
14
|
+
crop?: CropRect;
|
|
12
15
|
}
|
|
13
16
|
export interface AssetUrlOptions {
|
|
14
17
|
width?: number;
|
|
@@ -23,16 +26,14 @@ export interface AssetUrlOptions {
|
|
|
23
26
|
* option beside it. Two shapes are legitimate, and they are alternatives, never composed:
|
|
24
27
|
*
|
|
25
28
|
* - An absolute origin (`https://assets.example.com`) — assets served from another origin.
|
|
26
|
-
* `media.publicBaseUrl` is one source of this, and is the source the editor uses; it is
|
|
27
|
-
* validated as an absolute URL, so it structurally cannot carry the second shape.
|
|
28
29
|
* - A same-origin path prefix (`/preview-123`) — the site is deployed under a Next `basePath`
|
|
29
30
|
* AND its assets are served by Next (`withCanopy`'s `/assets/:path*` rewrite, which Next
|
|
30
31
|
* auto-prefixes). NOT the right value on a CloudFront/CDK deployment, where the asset
|
|
31
32
|
* behaviors are anchored at the distribution root and a `basePath` does not move them —
|
|
32
33
|
* there the correct value is none at all. See the README's asset-mount table.
|
|
33
34
|
*
|
|
34
|
-
* It is a per-render option rather than a config field
|
|
35
|
-
*
|
|
35
|
+
* It is a per-render option rather than a config field because different renderers see the
|
|
36
|
+
* `/assets` space at different places.
|
|
36
37
|
*
|
|
37
38
|
* **Render-time only — never stored.** A stored `src` is always root-relative (see
|
|
38
39
|
* `assets/asset-src.ts`), because content moves between branches and environments. Nothing
|
|
@@ -41,16 +42,21 @@ export interface AssetUrlOptions {
|
|
|
41
42
|
baseUrl?: string;
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
44
|
-
* Build a transform URL, merging `opts` over the directives already present
|
|
45
|
-
* in `ref.src` (
|
|
46
|
-
* or any src that isn't one of our own transform URLs) the src is
|
|
47
|
-
* unchanged and
|
|
45
|
+
* Build a transform URL, merging `opts` and `ref.crop` over the directives already present
|
|
46
|
+
* in `ref.src` (see `mergeDirectives` for precedence). For static srcs (svg/pdf under
|
|
47
|
+
* `/assets/{hash}/...`, or any src that isn't one of our own transform URLs) the src is
|
|
48
|
+
* returned unchanged and every directive is ignored - there is nothing to transform.
|
|
49
|
+
*
|
|
50
|
+
* In a live preview, a transform URL goes behind the editor's authenticated route
|
|
51
|
+
* (`editor/preview-asset-base.ts`) instead of `opts.baseUrl`: a draft's crop or width may exist
|
|
52
|
+
* nowhere a build put it. Static srcs keep `opts.baseUrl`, since finalize wrote them.
|
|
48
53
|
*/
|
|
49
54
|
export declare function assetUrl(ref: AssetRef, opts?: AssetUrlOptions): string;
|
|
50
55
|
/**
|
|
51
56
|
* Build a comma-joined `url w` srcset descriptor list. `widths` must all be
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
57
|
+
* integers in [1, 8192] (the `any` width policy) - this is developer-facing (a
|
|
58
|
+
* host app's own responsive-image markup), so an invalid width throws rather
|
|
59
|
+
* than silently dropping it. A site serving the opt-in lazy public path, which
|
|
60
|
+
* transforms only allowlisted widths, must pick widths from that allowlist.
|
|
55
61
|
*/
|
|
56
62
|
export declare function assetSrcSet(ref: AssetRef, widths: readonly number[], opts?: Omit<AssetUrlOptions, 'width'>): string;
|
package/dist/assets/asset-url.js
CHANGED
|
@@ -1,36 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Build/adjust transform URLs for `<img>`/srcset without pulling in the
|
|
3
|
-
* server-only transform engine. Isomorphic -
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* import from client (editor) code as well as during static builds.
|
|
3
|
+
* server-only transform engine. Isomorphic - none of its imports reach a node
|
|
4
|
+
* builtin, so this is safe to import from client (editor) code as well as during
|
|
5
|
+
* static builds.
|
|
7
6
|
*/
|
|
8
7
|
import { isUnprefixablePath, joinUrlPrefix, sanitizeUnprefixedPath, stripTrailingSlashes, } from '../utils/url-prefix.js';
|
|
8
|
+
import { getPreviewAssetBase } from '../editor/preview-asset-base.js';
|
|
9
9
|
import { ASSET_PREFIXES } from './asset-prefixes.js';
|
|
10
10
|
import { formatDirectives, isAllowedTransformWidth, parseTransformPath, } from './transform-directives.js';
|
|
11
11
|
const TRANSFORM_URL_PREFIX = `/${ASSET_PREFIXES.transform}/`;
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* opts - only to override it).
|
|
13
|
+
* Test-only. A function stored on `globalThis` under this symbol is called with every URL
|
|
14
|
+
* `assetUrl` returns; the dual-build fixture installs one during a static export to prove
|
|
15
|
+
* `collect-asset-refs` finds every URL its pages emitted.
|
|
17
16
|
*/
|
|
18
|
-
|
|
17
|
+
const EMITTED_URL_LISTENER = Symbol.for('canopycms.assetUrl.emitted');
|
|
18
|
+
function emitted(url) {
|
|
19
|
+
const listener = globalThis[EMITTED_URL_LISTENER];
|
|
20
|
+
if (typeof listener === 'function')
|
|
21
|
+
listener(url);
|
|
22
|
+
return url;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Merge `opts` and the ref's crop over the directives already in its src. Precedence per
|
|
26
|
+
* directive: `opts`, then `ref.crop` (crop only), then the src. There is no way to clear a
|
|
27
|
+
* directive, only to override it.
|
|
28
|
+
*/
|
|
29
|
+
function mergeDirectives(current, refCrop, opts) {
|
|
19
30
|
const existing = current.identity ? undefined : current;
|
|
20
31
|
const width = opts.width ?? existing?.width;
|
|
21
32
|
const format = opts.format ?? existing?.format;
|
|
22
33
|
const quality = opts.quality ?? existing?.quality;
|
|
23
|
-
const crop = opts.crop ?? existing?.crop;
|
|
34
|
+
const crop = opts.crop ?? refCrop ?? existing?.crop;
|
|
24
35
|
if (width === undefined && format === undefined && quality === undefined && crop === undefined) {
|
|
25
36
|
return { identity: true };
|
|
26
37
|
}
|
|
27
38
|
return { identity: false, width, format, quality, crop };
|
|
28
39
|
}
|
|
29
40
|
/**
|
|
30
|
-
* Build a transform URL, merging `opts` over the directives already present
|
|
31
|
-
* in `ref.src` (
|
|
32
|
-
* or any src that isn't one of our own transform URLs) the src is
|
|
33
|
-
* unchanged and
|
|
41
|
+
* Build a transform URL, merging `opts` and `ref.crop` over the directives already present
|
|
42
|
+
* in `ref.src` (see `mergeDirectives` for precedence). For static srcs (svg/pdf under
|
|
43
|
+
* `/assets/{hash}/...`, or any src that isn't one of our own transform URLs) the src is
|
|
44
|
+
* returned unchanged and every directive is ignored - there is nothing to transform.
|
|
45
|
+
*
|
|
46
|
+
* In a live preview, a transform URL goes behind the editor's authenticated route
|
|
47
|
+
* (`editor/preview-asset-base.ts`) instead of `opts.baseUrl`: a draft's crop or width may exist
|
|
48
|
+
* nowhere a build put it. Static srcs keep `opts.baseUrl`, since finalize wrote them.
|
|
34
49
|
*/
|
|
35
50
|
export function assetUrl(ref, opts = {}) {
|
|
36
51
|
const { src } = ref;
|
|
@@ -46,35 +61,37 @@ export function assetUrl(ref, opts = {}) {
|
|
|
46
61
|
// `joinUrlPrefix`'s own contract. Plain `!opts.baseUrl` made '' and '/' disagree.
|
|
47
62
|
const mount = opts.baseUrl ? stripTrailingSlashes(opts.baseUrl) : '';
|
|
48
63
|
if (!mount || isUnprefixablePath(src))
|
|
49
|
-
return sanitizeUnprefixedPath(src);
|
|
50
|
-
return joinUrlPrefix(opts.baseUrl, src);
|
|
64
|
+
return emitted(sanitizeUnprefixedPath(src));
|
|
65
|
+
return emitted(joinUrlPrefix(opts.baseUrl, src));
|
|
51
66
|
}
|
|
67
|
+
const base = getPreviewAssetBase() ?? opts.baseUrl;
|
|
52
68
|
const rest = src.slice(TRANSFORM_URL_PREFIX.length);
|
|
53
|
-
const parsed = parseTransformPath(rest.split('/'));
|
|
69
|
+
const parsed = parseTransformPath(rest.split('/'), 'any');
|
|
54
70
|
if (!parsed.ok) {
|
|
55
71
|
// Malformed src (shouldn't happen for a src canopycms itself wrote) -
|
|
56
72
|
// nothing sensible to merge onto, so return it unchanged rather than throw.
|
|
57
|
-
return joinUrlPrefix(
|
|
73
|
+
return emitted(joinUrlPrefix(base, src));
|
|
58
74
|
}
|
|
59
|
-
const merged = mergeDirectives(parsed.directives, opts);
|
|
75
|
+
const merged = mergeDirectives(parsed.directives, ref.crop, opts);
|
|
60
76
|
// Ext follows the format: an explicit format (new or carried over) always
|
|
61
77
|
// wins; with no format at all, the ext must keep preserving the source's
|
|
62
78
|
// real extension, which is exactly what `parsed.ext` already is here.
|
|
63
79
|
const ext = !merged.identity && merged.format !== undefined ? merged.format : parsed.ext;
|
|
64
80
|
const newSrc = `${TRANSFORM_URL_PREFIX}${formatDirectives(merged)}/${parsed.hash32}/${parsed.slug}.${ext}`;
|
|
65
|
-
return joinUrlPrefix(
|
|
81
|
+
return emitted(joinUrlPrefix(base, newSrc));
|
|
66
82
|
}
|
|
67
83
|
/**
|
|
68
84
|
* Build a comma-joined `url w` srcset descriptor list. `widths` must all be
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
85
|
+
* integers in [1, 8192] (the `any` width policy) - this is developer-facing (a
|
|
86
|
+
* host app's own responsive-image markup), so an invalid width throws rather
|
|
87
|
+
* than silently dropping it. A site serving the opt-in lazy public path, which
|
|
88
|
+
* transforms only allowlisted widths, must pick widths from that allowlist.
|
|
72
89
|
*/
|
|
73
90
|
export function assetSrcSet(ref, widths, opts = {}) {
|
|
74
91
|
return widths
|
|
75
92
|
.map((width) => {
|
|
76
|
-
if (!isAllowedTransformWidth(width)) {
|
|
77
|
-
throw new Error(`assetSrcSet: width ${width} is not allowed (must be
|
|
93
|
+
if (!isAllowedTransformWidth(width, 'any')) {
|
|
94
|
+
throw new Error(`assetSrcSet: width ${width} is not allowed (must be an integer between 1 and 8192)`);
|
|
78
95
|
}
|
|
79
96
|
return `${assetUrl(ref, { ...opts, width })} ${width}w`;
|
|
80
97
|
})
|
package/dist/assets/factory.d.ts
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This is the one place that turns the (currently-unconsumed) `media` config
|
|
5
5
|
* into a real store — see .claude/future-tasks/resolved/assets-media-system.md.
|
|
6
|
+
*
|
|
7
|
+
* The store is branch-agnostic: a local one is rooted at the dev workspace's
|
|
8
|
+
* `assets/` or at `media.directory` resolved against the process's working
|
|
9
|
+
* directory, never inside a branch clone. So asset writes take no [SYNC-C1]
|
|
10
|
+
* content-write lock — the worker's rebase never touches them.
|
|
6
11
|
*/
|
|
7
12
|
import type { MediaConfig } from '../config/types.js';
|
|
8
13
|
import type { AssetStore } from './types.js';
|
package/dist/assets/factory.js
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This is the one place that turns the (currently-unconsumed) `media` config
|
|
5
5
|
* into a real store — see .claude/future-tasks/resolved/assets-media-system.md.
|
|
6
|
+
*
|
|
7
|
+
* The store is branch-agnostic: a local one is rooted at the dev workspace's
|
|
8
|
+
* `assets/` or at `media.directory` resolved against the process's working
|
|
9
|
+
* directory, never inside a branch clone. So asset writes take no [SYNC-C1]
|
|
10
|
+
* content-write lock — the worker's rebase never touches them.
|
|
6
11
|
*/
|
|
7
12
|
import { LocalAssetStore } from './store-local.js';
|
|
8
13
|
import { S3AssetStore } from './store-s3.js';
|
package/dist/assets/finalize.js
CHANGED
|
@@ -39,6 +39,9 @@ export async function finalizeAsset(store, input) {
|
|
|
39
39
|
const existing = await store.getMeta(meta.hash32);
|
|
40
40
|
if (existing)
|
|
41
41
|
return { ok: true, meta: existing };
|
|
42
|
+
// Either put may find its key taken (`already-exists`): by an earlier attempt that stopped
|
|
43
|
+
// before the meta commit, or by a concurrent identical upload. The object kept there is this
|
|
44
|
+
// content's, so finalize goes on to commit the meta either way.
|
|
42
45
|
await store.putOriginal({ hash32: meta.hash32, ext: meta.ext, data, contentType: meta.mime });
|
|
43
46
|
if (publicObject) {
|
|
44
47
|
await store.putPublicObject(publicObject);
|
package/dist/assets/index.d.ts
CHANGED
|
@@ -14,6 +14,6 @@ export { ALLOWED_UPLOAD_CONTENT_TYPES, runFinalizePipeline, type FinalizeInput,
|
|
|
14
14
|
export { finalizeAsset, finalizeStagedUpload, type FinalizeAssetResult } from './finalize.js';
|
|
15
15
|
export { sanitizeSvg } from './svg-sanitizer.js';
|
|
16
16
|
export { assetSrc } from './asset-src.js';
|
|
17
|
-
export { formatDirectives, isAllowedTransformWidth, isValidCropRect, parseTransformPath, type CropRect, type OutputFormat, type ParsedTransformPath, type ParseTransformPathResult, type TransformDirectives, } from './transform-directives.js';
|
|
17
|
+
export { formatDirectives, isAllowedTransformWidth, isValidCropRect, parseTransformPath, type CropRect, type OutputFormat, type ParsedTransformPath, type ParseTransformPathResult, type TransformDirectives, type TransformWidthPolicy, } from './transform-directives.js';
|
|
18
18
|
export { applyTransform, type ApplyTransformInput, type TransformResult } from './transform.js';
|
|
19
19
|
export { assetUrl, assetSrcSet, type AssetRef, type AssetUrlOptions } from './asset-url.js';
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writing transform outputs into the store. Server-only.
|
|
3
|
+
*
|
|
4
|
+
* `storeTransform` computes one key and is shared by the authenticated raw route
|
|
5
|
+
* (api/assets.ts), `materializeAssets` (the batch run that writes every key a build references
|
|
6
|
+
* before that build is released) and canopycms-cdk's lazy transform Lambda.
|
|
7
|
+
*/
|
|
8
|
+
import { type ParsedTransformPath } from './transform-directives.js';
|
|
9
|
+
import type { AssetStore, CreateOnlyResult } from './types.js';
|
|
10
|
+
/** Every transform output is stored under a content-addressed key, so it never changes. */
|
|
11
|
+
export declare const TRANSFORM_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
12
|
+
/**
|
|
13
|
+
* The object tag on every derivative the lazy transform Lambda writes. Its bucket's `assets/t/`
|
|
14
|
+
* expiry filters on it, so what `materializeAssets` writes, which the Lambda's allowlist may refuse
|
|
15
|
+
* to recompute, is never expired. canopycms-cdk's `AssetSupport` copies these two strings as
|
|
16
|
+
* literals.
|
|
17
|
+
*/
|
|
18
|
+
export declare const LAZY_TRANSFORM_TAG: {
|
|
19
|
+
readonly key: "canopy-transform";
|
|
20
|
+
readonly value: "lazy";
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* `data` is the computed output whether or not it was stored: `stored: 'already-exists'` means
|
|
24
|
+
* another writer stored the key first, and the store kept that object.
|
|
25
|
+
*/
|
|
26
|
+
export type StoreTransformResult = {
|
|
27
|
+
ok: true;
|
|
28
|
+
data: Uint8Array;
|
|
29
|
+
contentType: string;
|
|
30
|
+
stored: CreateOnlyResult;
|
|
31
|
+
} | {
|
|
32
|
+
ok: false;
|
|
33
|
+
status: 400 | 404 | 413 | 422;
|
|
34
|
+
error: string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Compute the transform `parsed` names from the asset's original and write it under `key`: the
|
|
38
|
+
* canonical key, or that key beneath an output prefix. `parsed` must come from
|
|
39
|
+
* `canonicalizeTransformPath`, so the stored pixels always match their key. A rejection is a fact
|
|
40
|
+
* about the asset or the URL and is never worth retrying; a thrown error belongs to the store or
|
|
41
|
+
* the environment. A 404's `error` names what was missing, so a caller answering a browser
|
|
42
|
+
* replaces it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function storeTransform(store: AssetStore, parsed: ParsedTransformPath, key: string, options?: {
|
|
45
|
+
tags?: Readonly<Record<string, string>>;
|
|
46
|
+
}): Promise<StoreTransformResult>;
|
|
47
|
+
/** One key a build references, and where it was referenced, for the failure report. */
|
|
48
|
+
export interface MaterializeTarget {
|
|
49
|
+
/** `assets/t/{directives}/{hash32}/{slug}.{ext}`. */
|
|
50
|
+
key: string;
|
|
51
|
+
routes: readonly string[];
|
|
52
|
+
files: readonly string[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `content`: the key cannot be produced from what the store holds (asset deleted, wrong slug,
|
|
56
|
+
* undecodable input, malformed key), so a retry would fail the same way and the page must change.
|
|
57
|
+
* `store`: the store kept failing, or refused the request outright; rerunning may succeed.
|
|
58
|
+
*/
|
|
59
|
+
type MaterializeFailureKind = 'content' | 'store';
|
|
60
|
+
export type MaterializeResult = {
|
|
61
|
+
key: string;
|
|
62
|
+
routes: string[];
|
|
63
|
+
files: string[];
|
|
64
|
+
} & ({
|
|
65
|
+
status: 'existed' | 'created' | 'copied';
|
|
66
|
+
} | {
|
|
67
|
+
status: 'failed';
|
|
68
|
+
failure: MaterializeFailureKind;
|
|
69
|
+
error: string;
|
|
70
|
+
});
|
|
71
|
+
/** The `schemaVersion` of every `MaterializeReport`; a consumer gating on the JSON checks it. */
|
|
72
|
+
export declare const MATERIALIZE_REPORT_SCHEMA_VERSION = 1;
|
|
73
|
+
export interface MaterializeReport {
|
|
74
|
+
schemaVersion: typeof MATERIALIZE_REPORT_SCHEMA_VERSION;
|
|
75
|
+
/** `MaterializeOptions.outputPrefix`, present only when one was given. */
|
|
76
|
+
outputPrefix?: string;
|
|
77
|
+
summary: {
|
|
78
|
+
total: number;
|
|
79
|
+
existed: number;
|
|
80
|
+
created: number;
|
|
81
|
+
/** Keys copied from the canonical prefix into an output prefix; 0 until one is configured. */
|
|
82
|
+
copied: number;
|
|
83
|
+
failed: number;
|
|
84
|
+
contentFailures: number;
|
|
85
|
+
storeFailures: number;
|
|
86
|
+
};
|
|
87
|
+
/** Sorted by key. */
|
|
88
|
+
results: MaterializeResult[];
|
|
89
|
+
}
|
|
90
|
+
export interface MaterializeOptions {
|
|
91
|
+
store: AssetStore;
|
|
92
|
+
targets: readonly MaterializeTarget[];
|
|
93
|
+
/**
|
|
94
|
+
* `assets/{hash32}/{slug}.{ext}` keys (svg, pdf) a build references. These are never produced
|
|
95
|
+
* here (finalize writes them at upload), only checked, or copied under an `outputPrefix`, so a
|
|
96
|
+
* missing one is a content failure, unless the bucket itself is missing: a store failure.
|
|
97
|
+
*/
|
|
98
|
+
statics?: readonly MaterializeTarget[];
|
|
99
|
+
/**
|
|
100
|
+
* Write every key `k` at `outputPrefix + k` instead, for a build whose writes must never land
|
|
101
|
+
* where production reads (a PR preview). A key production already stores is copied from there;
|
|
102
|
+
* the rest are transformed from the canonical originals. Production's own run, with no prefix,
|
|
103
|
+
* never reads beneath it. See `assertValidOutputPrefix` for what is accepted.
|
|
104
|
+
*/
|
|
105
|
+
outputPrefix?: string;
|
|
106
|
+
/** Store requests in flight at once. Default 8. */
|
|
107
|
+
concurrency?: number;
|
|
108
|
+
/**
|
|
109
|
+
* Transforms in flight at once. Each holds a decoded image, up to about 1.2 GiB at
|
|
110
|
+
* `MAX_INPUT_PIXELS`, so this stays small whatever `concurrency` is. Default 2.
|
|
111
|
+
*/
|
|
112
|
+
transformConcurrency?: number;
|
|
113
|
+
/**
|
|
114
|
+
* A directive string referenced by at least this many keys has its whole `assets/t/{directives}/`
|
|
115
|
+
* prefix listed once instead of a HEAD per key, when the store can list. Default 100.
|
|
116
|
+
*/
|
|
117
|
+
listThreshold?: number;
|
|
118
|
+
/** Attempts per store operation, including the first. Default 3. */
|
|
119
|
+
attempts?: number;
|
|
120
|
+
/** First retry delay; each later one doubles. Default 500. */
|
|
121
|
+
baseDelayMs?: number;
|
|
122
|
+
/** @internal Test seam for the retry delay. */
|
|
123
|
+
sleep?: (ms: number) => Promise<void>;
|
|
124
|
+
}
|
|
125
|
+
/** sharp cannot load in this process, so nothing missing can be produced here. */
|
|
126
|
+
export declare class SharpUnavailableError extends Error {
|
|
127
|
+
constructor(cause: unknown);
|
|
128
|
+
}
|
|
129
|
+
/** `MaterializeOptions.outputPrefix` broke a rule of `assertValidOutputPrefix`; nothing was read or written. */
|
|
130
|
+
export declare class InvalidOutputPrefixError extends Error {
|
|
131
|
+
constructor(prefix: string, reason: string);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Throws `InvalidOutputPrefixError` unless `prefix` is relative, ends in `/`, and is a run of
|
|
135
|
+
* `[A-Za-z0-9._-]` segments, none empty, `.` or `..`, whose first segments are not a canopy
|
|
136
|
+
* prefix. Production trusts whatever is under its own prefixes, so a write beneath one is a write
|
|
137
|
+
* production serves. Compared by segment: `assets-x/` is accepted, `assets/x/` is not.
|
|
138
|
+
*/
|
|
139
|
+
export declare function assertValidOutputPrefix(prefix: string): void;
|
|
140
|
+
/**
|
|
141
|
+
* @internal Exported for tests. Throttling, 5xx and dropped connections are transient. Any other
|
|
142
|
+
* 4xx (AccessDenied, NoSuchBucket) is a configuration fault that a retry only delays.
|
|
143
|
+
*/
|
|
144
|
+
export declare function isTransientStoreError(err: unknown): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* Make every referenced transform key exist in `store`, and check every static key does. A key
|
|
147
|
+
* already stored is left alone:
|
|
148
|
+
* keys are content-addressed, so an existing object is the right one. sharp is loaded only when
|
|
149
|
+
* something must be transformed, and a sharp that cannot load throws `SharpUnavailableError` rather
|
|
150
|
+
* than failing each key. An invalid `outputPrefix` throws `InvalidOutputPrefixError` first.
|
|
151
|
+
*/
|
|
152
|
+
export declare function materializeAssets(options: MaterializeOptions): Promise<MaterializeReport>;
|
|
153
|
+
export {};
|