@sanity/cli 8.10.0 → 8.12.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 (63) hide show
  1. package/README.md +69 -26
  2. package/dist/actions/assets/ingestAssetFromUrlWithProgress.js +21 -0
  3. package/dist/actions/assets/ingestAssetFromUrlWithProgress.js.map +1 -0
  4. package/dist/actions/assets/withUrlIngestProgress.js +45 -0
  5. package/dist/actions/assets/withUrlIngestProgress.js.map +1 -0
  6. package/dist/actions/auth/authServer.js +5 -8
  7. package/dist/actions/auth/authServer.js.map +1 -1
  8. package/dist/actions/auth/login/getProvider.js +10 -14
  9. package/dist/actions/auth/login/getProvider.js.map +1 -1
  10. package/dist/actions/auth/login/login.js +0 -1
  11. package/dist/actions/auth/login/login.js.map +1 -1
  12. package/dist/actions/deploy/deployApp.js +5 -2
  13. package/dist/actions/deploy/deployApp.js.map +1 -1
  14. package/dist/actions/deploy/deployChecks.js +3 -2
  15. package/dist/actions/deploy/deployChecks.js.map +1 -1
  16. package/dist/actions/deploy/findUserApplication.js +3 -2
  17. package/dist/actions/deploy/findUserApplication.js.map +1 -1
  18. package/dist/actions/deploy/resolveDeployTarget.js +6 -1
  19. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  20. package/dist/actions/documents/validateDocuments.worker.js +1 -4
  21. package/dist/actions/documents/validateDocuments.worker.js.map +1 -1
  22. package/dist/actions/media/importMedia.js.map +1 -1
  23. package/dist/actions/media/ingestMediaAssetFromUrlWithProgress.js +19 -0
  24. package/dist/actions/media/ingestMediaAssetFromUrlWithProgress.js.map +1 -0
  25. package/dist/commands/assets/upload.js +78 -52
  26. package/dist/commands/assets/upload.js.map +1 -1
  27. package/dist/commands/deploy.js +33 -1
  28. package/dist/commands/deploy.js.map +1 -1
  29. package/dist/commands/media/import.js +149 -13
  30. package/dist/commands/media/import.js.map +1 -1
  31. package/dist/exports/invokeSanityCli/commandPolicies/index.js +1 -4
  32. package/dist/exports/invokeSanityCli/commandPolicies/index.js.map +1 -1
  33. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +26 -6
  34. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  35. package/dist/exports/invokeSanityCli/commandPolicies/resolve.js +112 -0
  36. package/dist/exports/invokeSanityCli/commandPolicies/resolve.js.map +1 -0
  37. package/dist/exports/invokeSanityCli/help.js +8 -1
  38. package/dist/exports/invokeSanityCli/help.js.map +1 -1
  39. package/dist/exports/invokeSanityCli/index.d.ts +1 -2
  40. package/dist/exports/invokeSanityCli/index.js +37 -15
  41. package/dist/exports/invokeSanityCli/index.js.map +1 -1
  42. package/dist/generated/apiRoutes.js +2 -0
  43. package/dist/generated/apiRoutes.js.map +1 -1
  44. package/dist/services/assets.js +46 -1
  45. package/dist/services/assets.js.map +1 -1
  46. package/dist/services/mediaLibraries.js +39 -1
  47. package/dist/services/mediaLibraries.js.map +1 -1
  48. package/dist/util/assetSourceValidation.js +56 -0
  49. package/dist/util/assetSourceValidation.js.map +1 -0
  50. package/dist/util/assetUploadErrors.js +64 -0
  51. package/dist/util/assetUploadErrors.js.map +1 -0
  52. package/dist/util/isRemoteAssetSource.js +19 -0
  53. package/dist/util/isRemoteAssetSource.js.map +1 -0
  54. package/dist/util/parseAspectFlags.js +34 -0
  55. package/dist/util/parseAspectFlags.js.map +1 -0
  56. package/oclif.config.js +0 -1
  57. package/oclif.manifest.json +2134 -2055
  58. package/package.json +18 -18
  59. package/templates/app-quickstart/AGENTS.md +18 -0
  60. package/templates/app-sanity-ui/AGENTS.md +18 -0
  61. package/templates/shopify/.gitignore +26 -0
  62. package/dist/exports/invokeSanityCli/commandPolicies/policy.js +0 -46
  63. package/dist/exports/invokeSanityCli/commandPolicies/policy.js.map +0 -1
@@ -0,0 +1,56 @@
1
+ const MAX_URL_LENGTH = 2048;
2
+ const MAX_FILENAME_LENGTH = 255;
3
+ /**
4
+ * Check a URL that Sanity will fetch an asset from.
5
+ *
6
+ * Sanity fetches the source itself, over https and without credentials, so a
7
+ * URL it cannot act on is worth rejecting here rather than spending a request
8
+ * to have it come back as an opaque server error.
9
+ *
10
+ * Embedded credentials are rejected rather than stripped: they would travel to
11
+ * Sanity and be recorded wherever the request is, and a presigned URL is the
12
+ * supported way to reach a source that needs authentication.
13
+ *
14
+ * @returns The problem with the URL, or `undefined` when it is usable.
15
+ *
16
+ * @internal
17
+ */ export function getIngestUrlError(url) {
18
+ if (url.length > MAX_URL_LENGTH) {
19
+ return `The asset URL must be ${MAX_URL_LENGTH} characters or fewer, but is ${url.length}. Shorten the URL, then try again.`;
20
+ }
21
+ if (!URL.canParse(url)) {
22
+ return `"${url}" is not a valid URL. Pass a full URL, such as https://example.com/hero.png.`;
23
+ }
24
+ const { password, protocol, username } = new URL(url);
25
+ if (protocol !== 'https:') {
26
+ return `The asset URL must use https, not "${protocol}". Sanity fetches the asset over the public internet.`;
27
+ }
28
+ if (username || password) {
29
+ return 'The asset URL must not contain a username or password. Use a presigned URL when the source needs authentication.';
30
+ }
31
+ return undefined;
32
+ }
33
+ /**
34
+ * Check a `--filename` value against what an asset document can store.
35
+ *
36
+ * Only validates a filename the user supplied. A filename derived from a local
37
+ * path is already a single path segment, and on POSIX it may legitimately
38
+ * contain the backslash rejected here.
39
+ *
40
+ * @returns The problem with the filename, or `undefined` when it is usable.
41
+ *
42
+ * @internal
43
+ */ export function getAssetFilenameError(filename) {
44
+ if (filename.length === 0) {
45
+ return '--filename must not be empty. Pass a filename, or omit the flag to let Sanity derive one.';
46
+ }
47
+ if (filename.length > MAX_FILENAME_LENGTH) {
48
+ return `--filename must be ${MAX_FILENAME_LENGTH} characters or fewer, but is ${filename.length}. Shorten the filename, then try again.`;
49
+ }
50
+ if (/[/\\\0]/.test(filename)) {
51
+ return '--filename must not contain path separators or null bytes. Pass the filename on its own, such as hero.png.';
52
+ }
53
+ return undefined;
54
+ }
55
+
56
+ //# sourceMappingURL=assetSourceValidation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/assetSourceValidation.ts"],"sourcesContent":["const MAX_URL_LENGTH = 2048\nconst MAX_FILENAME_LENGTH = 255\n\n/**\n * Check a URL that Sanity will fetch an asset from.\n *\n * Sanity fetches the source itself, over https and without credentials, so a\n * URL it cannot act on is worth rejecting here rather than spending a request\n * to have it come back as an opaque server error.\n *\n * Embedded credentials are rejected rather than stripped: they would travel to\n * Sanity and be recorded wherever the request is, and a presigned URL is the\n * supported way to reach a source that needs authentication.\n *\n * @returns The problem with the URL, or `undefined` when it is usable.\n *\n * @internal\n */\nexport function getIngestUrlError(url: string): string | undefined {\n if (url.length > MAX_URL_LENGTH) {\n return `The asset URL must be ${MAX_URL_LENGTH} characters or fewer, but is ${url.length}. Shorten the URL, then try again.`\n }\n\n if (!URL.canParse(url)) {\n return `\"${url}\" is not a valid URL. Pass a full URL, such as https://example.com/hero.png.`\n }\n\n const {password, protocol, username} = new URL(url)\n\n if (protocol !== 'https:') {\n return `The asset URL must use https, not \"${protocol}\". Sanity fetches the asset over the public internet.`\n }\n\n if (username || password) {\n return 'The asset URL must not contain a username or password. Use a presigned URL when the source needs authentication.'\n }\n\n return undefined\n}\n\n/**\n * Check a `--filename` value against what an asset document can store.\n *\n * Only validates a filename the user supplied. A filename derived from a local\n * path is already a single path segment, and on POSIX it may legitimately\n * contain the backslash rejected here.\n *\n * @returns The problem with the filename, or `undefined` when it is usable.\n *\n * @internal\n */\nexport function getAssetFilenameError(filename: string): string | undefined {\n if (filename.length === 0) {\n return '--filename must not be empty. Pass a filename, or omit the flag to let Sanity derive one.'\n }\n\n if (filename.length > MAX_FILENAME_LENGTH) {\n return `--filename must be ${MAX_FILENAME_LENGTH} characters or fewer, but is ${filename.length}. Shorten the filename, then try again.`\n }\n\n if (/[/\\\\\\0]/.test(filename)) {\n return '--filename must not contain path separators or null bytes. Pass the filename on its own, such as hero.png.'\n }\n\n return undefined\n}\n"],"names":["MAX_URL_LENGTH","MAX_FILENAME_LENGTH","getIngestUrlError","url","length","URL","canParse","password","protocol","username","undefined","getAssetFilenameError","filename","test"],"mappings":"AAAA,MAAMA,iBAAiB;AACvB,MAAMC,sBAAsB;AAE5B;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,kBAAkBC,GAAW;IAC3C,IAAIA,IAAIC,MAAM,GAAGJ,gBAAgB;QAC/B,OAAO,CAAC,sBAAsB,EAAEA,eAAe,6BAA6B,EAAEG,IAAIC,MAAM,CAAC,kCAAkC,CAAC;IAC9H;IAEA,IAAI,CAACC,IAAIC,QAAQ,CAACH,MAAM;QACtB,OAAO,CAAC,CAAC,EAAEA,IAAI,4EAA4E,CAAC;IAC9F;IAEA,MAAM,EAACI,QAAQ,EAAEC,QAAQ,EAAEC,QAAQ,EAAC,GAAG,IAAIJ,IAAIF;IAE/C,IAAIK,aAAa,UAAU;QACzB,OAAO,CAAC,mCAAmC,EAAEA,SAAS,qDAAqD,CAAC;IAC9G;IAEA,IAAIC,YAAYF,UAAU;QACxB,OAAO;IACT;IAEA,OAAOG;AACT;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASC,sBAAsBC,QAAgB;IACpD,IAAIA,SAASR,MAAM,KAAK,GAAG;QACzB,OAAO;IACT;IAEA,IAAIQ,SAASR,MAAM,GAAGH,qBAAqB;QACzC,OAAO,CAAC,mBAAmB,EAAEA,oBAAoB,6BAA6B,EAAEW,SAASR,MAAM,CAAC,uCAAuC,CAAC;IAC1I;IAEA,IAAI,UAAUS,IAAI,CAACD,WAAW;QAC5B,OAAO;IACT;IAEA,OAAOF;AACT"}
@@ -0,0 +1,64 @@
1
+ import { getErrorMessage } from '@sanity/cli-core/errors';
2
+ import { isHttpError } from '@sanity/client';
3
+ const DATASET_ASSET_LIMITS_URL = 'https://www.sanity.io/docs/content-lake/technical-limits#k2c53dc30e24b';
4
+ const MEDIA_LIBRARY_ASSET_LIMITS_URL = 'https://www.sanity.io/docs/media-library';
5
+ const TARGET_GUIDANCE = {
6
+ dataset: {
7
+ limitsUrl: DATASET_ASSET_LIMITS_URL,
8
+ writeAccessTo: 'this dataset'
9
+ },
10
+ 'media-library': {
11
+ limitsUrl: MEDIA_LIBRARY_ASSET_LIMITS_URL,
12
+ writeAccessTo: 'this media library'
13
+ }
14
+ };
15
+ function isProjectUserNotFoundError(body) {
16
+ const responseError = body.error;
17
+ return typeof responseError === 'object' && responseError !== null && 'type' in responseError && responseError.type === 'projectUserNotFoundError';
18
+ }
19
+ /**
20
+ * Turn an asset upload failure into a message that says what the API reported
21
+ * and what to do about it.
22
+ *
23
+ * @param error - The thrown error, HTTP or otherwise.
24
+ * @param options - `fromUrl` selects the gateway-failure guidance, which only
25
+ * makes sense when Content Lake was fetching the source itself; `target`
26
+ * selects the resource-specific wording.
27
+ *
28
+ * @internal
29
+ */ export function getAssetUploadErrorMessage(error, options) {
30
+ if (!isHttpError(error)) {
31
+ return `Asset upload failed: ${getErrorMessage(error)}`;
32
+ }
33
+ const { limitsUrl, writeAccessTo } = TARGET_GUIDANCE[options.target];
34
+ const body = typeof error.response.body === 'object' && error.response.body !== null && !Array.isArray(error.response.body) ? error.response.body : {};
35
+ const responseError = typeof body.error === 'string' ? body.error : error.response.statusMessage || 'HTTP error';
36
+ const statusCode = typeof body.statusCode === 'number' || typeof body.statusCode === 'string' ? body.statusCode : error.statusCode;
37
+ const projectUserNotFound = isProjectUserNotFoundError(body);
38
+ const responseMessage = projectUserNotFound ? error.message : getErrorMessage(error);
39
+ const message = /[.!?]$/.test(responseMessage) ? responseMessage : `${responseMessage}.`;
40
+ const details = typeof body.details === 'string' ? `\n\nDetails:\n${body.details}` : '';
41
+ const response = `Asset upload failed: HTTP ${statusCode} - ${responseError}\n${message}${details}`;
42
+ if (error.statusCode === 401 && !projectUserNotFound) {
43
+ return `${response}\n\nRun \`sanity login\` to authenticate, then try again.`;
44
+ }
45
+ if (error.statusCode === 403) {
46
+ return `${response}\n\nCheck that your account has write access to ${writeAccessTo}, then try again.`;
47
+ }
48
+ if ([
49
+ 400,
50
+ 413,
51
+ 422
52
+ ].includes(error.statusCode)) {
53
+ return `${response}\n\nCheck the asset requirements and current technical limits, then try again: ${limitsUrl}`;
54
+ }
55
+ if (options.fromUrl && [
56
+ 502,
57
+ 504
58
+ ].includes(error.statusCode)) {
59
+ return `${response}\n\nSanity could not fetch the source URL. Check that it is reachable from the public internet without authentication and serves the asset directly, then try again.`;
60
+ }
61
+ return `${response}\n\nTry again.`;
62
+ }
63
+
64
+ //# sourceMappingURL=assetUploadErrors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/assetUploadErrors.ts"],"sourcesContent":["import {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nconst DATASET_ASSET_LIMITS_URL =\n 'https://www.sanity.io/docs/content-lake/technical-limits#k2c53dc30e24b'\nconst MEDIA_LIBRARY_ASSET_LIMITS_URL = 'https://www.sanity.io/docs/media-library'\n\n/**\n * The asset store an upload targeted. Only affects guidance wording: which\n * resource the user needs write access to, and which limits to check.\n */\nexport type AssetUploadTarget = 'dataset' | 'media-library'\n\nconst TARGET_GUIDANCE: Record<AssetUploadTarget, {limitsUrl: string; writeAccessTo: string}> = {\n dataset: {limitsUrl: DATASET_ASSET_LIMITS_URL, writeAccessTo: 'this dataset'},\n 'media-library': {limitsUrl: MEDIA_LIBRARY_ASSET_LIMITS_URL, writeAccessTo: 'this media library'},\n}\n\nfunction isProjectUserNotFoundError(body: Record<string, unknown>): boolean {\n const responseError = body.error\n return (\n typeof responseError === 'object' &&\n responseError !== null &&\n 'type' in responseError &&\n responseError.type === 'projectUserNotFoundError'\n )\n}\n\n/**\n * Turn an asset upload failure into a message that says what the API reported\n * and what to do about it.\n *\n * @param error - The thrown error, HTTP or otherwise.\n * @param options - `fromUrl` selects the gateway-failure guidance, which only\n * makes sense when Content Lake was fetching the source itself; `target`\n * selects the resource-specific wording.\n *\n * @internal\n */\nexport function getAssetUploadErrorMessage(\n error: unknown,\n options: {fromUrl: boolean; target: AssetUploadTarget},\n): string {\n if (!isHttpError(error)) {\n return `Asset upload failed: ${getErrorMessage(error)}`\n }\n\n const {limitsUrl, writeAccessTo} = TARGET_GUIDANCE[options.target]\n\n const body =\n typeof error.response.body === 'object' &&\n error.response.body !== null &&\n !Array.isArray(error.response.body)\n ? (error.response.body as Record<string, unknown>)\n : {}\n\n const responseError =\n typeof body.error === 'string' ? body.error : error.response.statusMessage || 'HTTP error'\n\n const statusCode =\n typeof body.statusCode === 'number' || typeof body.statusCode === 'string'\n ? body.statusCode\n : error.statusCode\n\n const projectUserNotFound = isProjectUserNotFoundError(body)\n const responseMessage = projectUserNotFound ? error.message : getErrorMessage(error)\n const message = /[.!?]$/.test(responseMessage) ? responseMessage : `${responseMessage}.`\n const details = typeof body.details === 'string' ? `\\n\\nDetails:\\n${body.details}` : ''\n const response = `Asset upload failed: HTTP ${statusCode} - ${responseError}\\n${message}${details}`\n\n if (error.statusCode === 401 && !projectUserNotFound) {\n return `${response}\\n\\nRun \\`sanity login\\` to authenticate, then try again.`\n }\n if (error.statusCode === 403) {\n return `${response}\\n\\nCheck that your account has write access to ${writeAccessTo}, then try again.`\n }\n if ([400, 413, 422].includes(error.statusCode)) {\n return `${response}\\n\\nCheck the asset requirements and current technical limits, then try again: ${limitsUrl}`\n }\n if (options.fromUrl && [502, 504].includes(error.statusCode)) {\n return `${response}\\n\\nSanity could not fetch the source URL. Check that it is reachable from the public internet without authentication and serves the asset directly, then try again.`\n }\n return `${response}\\n\\nTry again.`\n}\n"],"names":["getErrorMessage","isHttpError","DATASET_ASSET_LIMITS_URL","MEDIA_LIBRARY_ASSET_LIMITS_URL","TARGET_GUIDANCE","dataset","limitsUrl","writeAccessTo","isProjectUserNotFoundError","body","responseError","error","type","getAssetUploadErrorMessage","options","target","response","Array","isArray","statusMessage","statusCode","projectUserNotFound","responseMessage","message","test","details","includes","fromUrl"],"mappings":"AAAA,SAAQA,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,MAAMC,2BACJ;AACF,MAAMC,iCAAiC;AAQvC,MAAMC,kBAAyF;IAC7FC,SAAS;QAACC,WAAWJ;QAA0BK,eAAe;IAAc;IAC5E,iBAAiB;QAACD,WAAWH;QAAgCI,eAAe;IAAoB;AAClG;AAEA,SAASC,2BAA2BC,IAA6B;IAC/D,MAAMC,gBAAgBD,KAAKE,KAAK;IAChC,OACE,OAAOD,kBAAkB,YACzBA,kBAAkB,QAClB,UAAUA,iBACVA,cAAcE,IAAI,KAAK;AAE3B;AAEA;;;;;;;;;;CAUC,GACD,OAAO,SAASC,2BACdF,KAAc,EACdG,OAAsD;IAEtD,IAAI,CAACb,YAAYU,QAAQ;QACvB,OAAO,CAAC,qBAAqB,EAAEX,gBAAgBW,QAAQ;IACzD;IAEA,MAAM,EAACL,SAAS,EAAEC,aAAa,EAAC,GAAGH,eAAe,CAACU,QAAQC,MAAM,CAAC;IAElE,MAAMN,OACJ,OAAOE,MAAMK,QAAQ,CAACP,IAAI,KAAK,YAC/BE,MAAMK,QAAQ,CAACP,IAAI,KAAK,QACxB,CAACQ,MAAMC,OAAO,CAACP,MAAMK,QAAQ,CAACP,IAAI,IAC7BE,MAAMK,QAAQ,CAACP,IAAI,GACpB,CAAC;IAEP,MAAMC,gBACJ,OAAOD,KAAKE,KAAK,KAAK,WAAWF,KAAKE,KAAK,GAAGA,MAAMK,QAAQ,CAACG,aAAa,IAAI;IAEhF,MAAMC,aACJ,OAAOX,KAAKW,UAAU,KAAK,YAAY,OAAOX,KAAKW,UAAU,KAAK,WAC9DX,KAAKW,UAAU,GACfT,MAAMS,UAAU;IAEtB,MAAMC,sBAAsBb,2BAA2BC;IACvD,MAAMa,kBAAkBD,sBAAsBV,MAAMY,OAAO,GAAGvB,gBAAgBW;IAC9E,MAAMY,UAAU,SAASC,IAAI,CAACF,mBAAmBA,kBAAkB,GAAGA,gBAAgB,CAAC,CAAC;IACxF,MAAMG,UAAU,OAAOhB,KAAKgB,OAAO,KAAK,WAAW,CAAC,cAAc,EAAEhB,KAAKgB,OAAO,EAAE,GAAG;IACrF,MAAMT,WAAW,CAAC,0BAA0B,EAAEI,WAAW,GAAG,EAAEV,cAAc,EAAE,EAAEa,UAAUE,SAAS;IAEnG,IAAId,MAAMS,UAAU,KAAK,OAAO,CAACC,qBAAqB;QACpD,OAAO,GAAGL,SAAS,yDAAyD,CAAC;IAC/E;IACA,IAAIL,MAAMS,UAAU,KAAK,KAAK;QAC5B,OAAO,GAAGJ,SAAS,gDAAgD,EAAET,cAAc,iBAAiB,CAAC;IACvG;IACA,IAAI;QAAC;QAAK;QAAK;KAAI,CAACmB,QAAQ,CAACf,MAAMS,UAAU,GAAG;QAC9C,OAAO,GAAGJ,SAAS,+EAA+E,EAAEV,WAAW;IACjH;IACA,IAAIQ,QAAQa,OAAO,IAAI;QAAC;QAAK;KAAI,CAACD,QAAQ,CAACf,MAAMS,UAAU,GAAG;QAC5D,OAAO,GAAGJ,SAAS,oKAAoK,CAAC;IAC1L;IACA,OAAO,GAAGA,SAAS,cAAc,CAAC;AACpC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Whether a command's source argument names a remote asset for Content Lake to
3
+ * fetch, rather than a path on the local filesystem.
4
+ *
5
+ * The protocol allowlist is load-bearing rather than defensive: a Windows path
6
+ * parses as a URL whose protocol is its drive letter (`C:\media` → `c:`), so
7
+ * matching on parseability alone would route local imports to the network.
8
+ * Anything else, `file:` included, is treated as a local path.
9
+ *
10
+ * `http:` counts as remote even though Content Lake only fetches over `https:`,
11
+ * so that an insecure URL reaches `getIngestUrlError` and is reported as one,
12
+ * rather than being stat'ed as a directory that does not exist.
13
+ */ export function isRemoteAssetSource(source) {
14
+ if (!URL.canParse(source)) return false;
15
+ const { protocol } = new URL(source);
16
+ return protocol === 'http:' || protocol === 'https:';
17
+ }
18
+
19
+ //# sourceMappingURL=isRemoteAssetSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/isRemoteAssetSource.ts"],"sourcesContent":["/**\n * Whether a command's source argument names a remote asset for Content Lake to\n * fetch, rather than a path on the local filesystem.\n *\n * The protocol allowlist is load-bearing rather than defensive: a Windows path\n * parses as a URL whose protocol is its drive letter (`C:\\media` → `c:`), so\n * matching on parseability alone would route local imports to the network.\n * Anything else, `file:` included, is treated as a local path.\n *\n * `http:` counts as remote even though Content Lake only fetches over `https:`,\n * so that an insecure URL reaches `getIngestUrlError` and is reported as one,\n * rather than being stat'ed as a directory that does not exist.\n */\nexport function isRemoteAssetSource(source: string): boolean {\n if (!URL.canParse(source)) return false\n const {protocol} = new URL(source)\n return protocol === 'http:' || protocol === 'https:'\n}\n"],"names":["isRemoteAssetSource","source","URL","canParse","protocol"],"mappings":"AAAA;;;;;;;;;;;;CAYC,GACD,OAAO,SAASA,oBAAoBC,MAAc;IAChD,IAAI,CAACC,IAAIC,QAAQ,CAACF,SAAS,OAAO;IAClC,MAAM,EAACG,QAAQ,EAAC,GAAG,IAAIF,IAAID;IAC3B,OAAOG,aAAa,WAAWA,aAAa;AAC9C"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Parsed `--aspect` values, or the message explaining which occurrence was
3
+ * malformed. Returned rather than thrown so the caller decides the exit code.
4
+ */ /**
5
+ * Assemble repeated `--aspect key=value` flags into the aspects object the
6
+ * media library ingest endpoint accepts.
7
+ *
8
+ * Values stay strings: the CLI has no access to the aspect definitions, so
9
+ * coercing `42` or `true` would guess at the target field's type. Aspects
10
+ * needing non-string or nested values belong in the `data.ndjson` of a
11
+ * directory import.
12
+ *
13
+ * Later occurrences of a key win, matching how `--header` and the NDJSON
14
+ * aspect index resolve duplicates.
15
+ *
16
+ * @internal
17
+ */ export function parseAspectFlags(aspectFlags) {
18
+ // Null-prototype so an aspect named e.g. `constructor` cannot reach Object.prototype
19
+ const aspects = Object.create(null);
20
+ for (const aspect of aspectFlags){
21
+ const separatorIndex = aspect.indexOf('=');
22
+ if (separatorIndex < 1) {
23
+ return {
24
+ error: `Invalid --aspect "${aspect}": expected key=value format`
25
+ };
26
+ }
27
+ aspects[aspect.slice(0, separatorIndex).trim()] = aspect.slice(separatorIndex + 1);
28
+ }
29
+ return {
30
+ aspects
31
+ };
32
+ }
33
+
34
+ //# sourceMappingURL=parseAspectFlags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/parseAspectFlags.ts"],"sourcesContent":["/**\n * Parsed `--aspect` values, or the message explaining which occurrence was\n * malformed. Returned rather than thrown so the caller decides the exit code.\n */\ntype ParseAspectFlagsResult = {aspects: Record<string, string>} | {error: string}\n\n/**\n * Assemble repeated `--aspect key=value` flags into the aspects object the\n * media library ingest endpoint accepts.\n *\n * Values stay strings: the CLI has no access to the aspect definitions, so\n * coercing `42` or `true` would guess at the target field's type. Aspects\n * needing non-string or nested values belong in the `data.ndjson` of a\n * directory import.\n *\n * Later occurrences of a key win, matching how `--header` and the NDJSON\n * aspect index resolve duplicates.\n *\n * @internal\n */\nexport function parseAspectFlags(aspectFlags: readonly string[]): ParseAspectFlagsResult {\n // Null-prototype so an aspect named e.g. `constructor` cannot reach Object.prototype\n const aspects: Record<string, string> = Object.create(null)\n\n for (const aspect of aspectFlags) {\n const separatorIndex = aspect.indexOf('=')\n if (separatorIndex < 1) {\n return {error: `Invalid --aspect \"${aspect}\": expected key=value format`}\n }\n aspects[aspect.slice(0, separatorIndex).trim()] = aspect.slice(separatorIndex + 1)\n }\n\n return {aspects}\n}\n"],"names":["parseAspectFlags","aspectFlags","aspects","Object","create","aspect","separatorIndex","indexOf","error","slice","trim"],"mappings":"AAAA;;;CAGC,GAGD;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASA,iBAAiBC,WAA8B;IAC7D,qFAAqF;IACrF,MAAMC,UAAkCC,OAAOC,MAAM,CAAC;IAEtD,KAAK,MAAMC,UAAUJ,YAAa;QAChC,MAAMK,iBAAiBD,OAAOE,OAAO,CAAC;QACtC,IAAID,iBAAiB,GAAG;YACtB,OAAO;gBAACE,OAAO,CAAC,kBAAkB,EAAEH,OAAO,4BAA4B,CAAC;YAAA;QAC1E;QACAH,OAAO,CAACG,OAAOI,KAAK,CAAC,GAAGH,gBAAgBI,IAAI,GAAG,GAAGL,OAAOI,KAAK,CAACH,iBAAiB;IAClF;IAEA,OAAO;QAACJ;IAAO;AACjB"}
package/oclif.config.js CHANGED
@@ -36,7 +36,6 @@ export default {
36
36
  tokens: {description: 'Manage API tokens for your project'},
37
37
  typegen: {description: 'Generate TypeScript types for schema and GROQ'},
38
38
  users: {description: 'Manage project users and invitations'},
39
- workflows: {hidden: true},
40
39
  },
41
40
  topicSeparator: ' ',
42
41
  }