@sanity/cli 6.2.0 → 6.2.1
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 +292 -287
- package/dist/actions/manifest/__tests__/testHelpers.js +21 -0
- package/dist/actions/manifest/__tests__/testHelpers.js.map +1 -0
- package/dist/actions/manifest/schemaTypeTransformer.js +2 -1
- package/dist/actions/manifest/schemaTypeTransformer.js.map +1 -1
- package/dist/commands/datasets/import.js +11 -10
- package/dist/commands/datasets/import.js.map +1 -1
- package/dist/services/telemetry.js +23 -2
- package/dist/services/telemetry.js.map +1 -1
- package/dist/util/packageManager/packageManagerChoice.js +1 -2
- package/dist/util/packageManager/packageManagerChoice.js.map +1 -1
- package/oclif.manifest.json +8 -4
- package/package.json +15 -15
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Schema } from '@sanity/schema';
|
|
2
|
+
import { transformType } from '../schemaTypeTransformer.js';
|
|
3
|
+
const defaultTypeNames = new Set(Schema.compile({
|
|
4
|
+
name: 'default',
|
|
5
|
+
types: []
|
|
6
|
+
}).getTypeNames());
|
|
7
|
+
/**
|
|
8
|
+
* Compiles a schema from user-defined types and extracts only the user-defined types
|
|
9
|
+
* as ManifestSchemaType[], filtering out Sanity's built-in types.
|
|
10
|
+
*/ export function extractTypes(types) {
|
|
11
|
+
const schema = Schema.compile({
|
|
12
|
+
name: 'test',
|
|
13
|
+
types
|
|
14
|
+
});
|
|
15
|
+
const context = {
|
|
16
|
+
schema
|
|
17
|
+
};
|
|
18
|
+
return schema.getTypeNames().filter((name)=>!defaultTypeNames.has(name)).map((name)=>transformType(schema.get(name), context));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=testHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/actions/manifest/__tests__/testHelpers.ts"],"sourcesContent":["import {Schema} from '@sanity/schema'\n\nimport {transformType} from '../schemaTypeTransformer.js'\nimport {type ManifestSchemaType} from '../types.js'\n\nconst defaultTypeNames = new Set(\n Schema.compile({name: 'default', types: []}).getTypeNames() as string[],\n)\n\n/**\n * Compiles a schema from user-defined types and extracts only the user-defined types\n * as ManifestSchemaType[], filtering out Sanity's built-in types.\n */\nexport function extractTypes(types: unknown[]): ManifestSchemaType[] {\n const schema = Schema.compile({name: 'test', types})\n const context = {schema}\n return (schema.getTypeNames() as string[])\n .filter((name: string) => !defaultTypeNames.has(name))\n .map((name: string) => transformType(schema.get(name), context))\n}\n"],"names":["Schema","transformType","defaultTypeNames","Set","compile","name","types","getTypeNames","extractTypes","schema","context","filter","has","map","get"],"mappings":"AAAA,SAAQA,MAAM,QAAO,iBAAgB;AAErC,SAAQC,aAAa,QAAO,8BAA6B;AAGzD,MAAMC,mBAAmB,IAAIC,IAC3BH,OAAOI,OAAO,CAAC;IAACC,MAAM;IAAWC,OAAO,EAAE;AAAA,GAAGC,YAAY;AAG3D;;;CAGC,GACD,OAAO,SAASC,aAAaF,KAAgB;IAC3C,MAAMG,SAAST,OAAOI,OAAO,CAAC;QAACC,MAAM;QAAQC;IAAK;IAClD,MAAMI,UAAU;QAACD;IAAM;IACvB,OAAO,AAACA,OAAOF,YAAY,GACxBI,MAAM,CAAC,CAACN,OAAiB,CAACH,iBAAiBU,GAAG,CAACP,OAC/CQ,GAAG,CAAC,CAACR,OAAiBJ,cAAcQ,OAAOK,GAAG,CAACT,OAAOK;AAC3D"}
|
|
@@ -100,7 +100,8 @@ const MAX_CUSTOM_PROPERTY_DEPTH = 5;
|
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* Retains serializable properties from an unknown value, recursively processing objects and arrays
|
|
103
|
-
|
|
103
|
+
* @internal Exported for testing purposes only
|
|
104
|
+
*/ export function retainSerializableProps(maybeSerializable, depth = 0) {
|
|
104
105
|
if (depth > MAX_CUSTOM_PROPERTY_DEPTH) {
|
|
105
106
|
return undefined;
|
|
106
107
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/manifest/schemaTypeTransformer.ts"],"sourcesContent":["import {\n type ArraySchemaType,\n type BlockDefinition,\n type BooleanSchemaType,\n type FileSchemaType,\n type MultiFieldSet,\n type NumberSchemaType,\n type ObjectField,\n type ObjectSchemaType,\n type ReferenceSchemaType,\n type SchemaType,\n type StringSchemaType,\n} from '@sanity/types'\n\nimport {transformBlockType} from './blockTypeTransformer.js'\nimport {\n transformCrossDatasetReference,\n transformGlobalDocumentReference,\n transformReference,\n} from './referenceTransformer.js'\nimport {\n getCustomFields,\n getDefinedTypeName,\n isCrossDatasetReference,\n isCustomized,\n isDefined,\n isGlobalDocumentReference,\n isPrimitive,\n isRecord,\n isReference,\n} from './schemaTypeHelpers.js'\nimport {\n type Context,\n ensureConditional,\n ensureCustomTitle,\n ensureString,\n type SerializableProp,\n} from './transformerUtils.js'\nimport {\n type ManifestField,\n type ManifestFieldset,\n type ManifestSchemaType,\n type ManifestSerializable,\n} from './types.js'\nimport {transformValidation} from './validationTransformer.js'\n\ntype SchemaTypeKey =\n | 'group' // we strip this from fields\n | keyof ArraySchemaType\n | keyof BlockDefinition\n | keyof BooleanSchemaType\n | keyof FileSchemaType\n | keyof NumberSchemaType\n | keyof ObjectSchemaType\n | keyof ReferenceSchemaType\n | keyof StringSchemaType\n\ntype ObjectFields = Record<string, never> | {fields: ManifestField[]}\n\nconst MAX_CUSTOM_PROPERTY_DEPTH = 5\n\n/**\n * Transforms a SchemaType to its manifest representation\n */\nexport function transformType(type: SchemaType, context: Context): ManifestSchemaType {\n const typeName = type.type ? type.type.name : type.jsonType\n\n return {\n ...transformCommonTypeFields(type, typeName, context),\n name: type.name,\n type: typeName,\n ...ensureCustomTitle(type.name, type.title),\n }\n}\n\n/**\n * Transforms common fields shared across all schema types\n */\nfunction transformCommonTypeFields(\n type: SchemaType & {fieldset?: string},\n typeName: string,\n context: Context,\n): Omit<ManifestSchemaType, 'name' | 'title' | 'type'> {\n const arrayProps =\n typeName === 'array' && type.jsonType === 'array' ? transformArrayMember(type, context) : {}\n\n const referenceProps = isReference(type) ? transformReference(type, retainCustomTypeProps) : {}\n const crossDatasetRefProps = isCrossDatasetReference(type)\n ? transformCrossDatasetReference(type)\n : {}\n const globalRefProps = isGlobalDocumentReference(type)\n ? transformGlobalDocumentReference(type)\n : {}\n\n const objectFields: ObjectFields =\n type.jsonType === 'object' && type.type && isCustomized(type)\n ? {\n fields: getCustomFields(type).map((objectField) => transformField(objectField, context)),\n }\n : {}\n\n return {\n ...retainCustomTypeProps(type),\n ...transformValidation(type.validation, retainSerializableProps),\n ...ensureString('description', type.description),\n ...objectFields,\n ...arrayProps,\n ...referenceProps,\n ...crossDatasetRefProps,\n ...globalRefProps,\n ...ensureConditional('readOnly', type.readOnly),\n ...ensureConditional('hidden', type.hidden),\n ...transformFieldsets(type),\n // fieldset prop gets instrumented via getCustomFields\n ...ensureString('fieldset', type.fieldset),\n ...transformBlockType(type, context, transformType),\n }\n}\n\n/**\n * Transforms fieldsets from a schema type\n */\nfunction transformFieldsets(\n type: SchemaType,\n): Record<string, never> | {fieldsets: ManifestFieldset[]} {\n if (type.jsonType !== 'object') {\n return {}\n }\n const fieldsets = type.fieldsets\n ?.filter((fs): fs is MultiFieldSet => !fs.single)\n .map((fs) => {\n const options = isRecord(fs.options) ? {options: retainSerializableProps(fs.options)} : {}\n return {\n name: fs.name,\n ...ensureCustomTitle(fs.name, fs.title),\n ...ensureString('description', fs.description),\n ...ensureConditional('readOnly', fs.readOnly),\n ...ensureConditional('hidden', fs.hidden),\n ...options,\n }\n })\n\n return fieldsets?.length ? {fieldsets} : {}\n}\n\n/**\n * Retains custom type properties that should be included in the manifest\n */\nfunction retainCustomTypeProps(type: SchemaType): Record<string, SerializableProp> {\n const manuallySerializedFields = new Set<SchemaTypeKey>([\n '__experimental_actions',\n '__experimental_formPreviewTitle',\n '__experimental_omnisearch_visibility',\n '__experimental_search',\n 'components',\n 'description',\n 'fields',\n 'fieldsets',\n //only exists on fields\n 'group',\n 'groups',\n 'hidden',\n 'icon',\n 'jsonType',\n //explicitly added\n 'name',\n 'of',\n 'orderings',\n 'preview',\n 'readOnly',\n 'title',\n 'to',\n // not serialized\n 'type',\n 'validation',\n // we know about these, but let them be generically handled\n // deprecated\n // rows (from text)\n // initialValue\n // options\n // crossDatasetReference props\n ])\n const typeWithoutManuallyHandledFields = Object.fromEntries(\n Object.entries(type).filter(\n ([key]) => !manuallySerializedFields.has(key as unknown as SchemaTypeKey),\n ),\n )\n return retainSerializableProps(typeWithoutManuallyHandledFields) as Record<\n string,\n SerializableProp\n >\n}\n\n/**\n * Retains serializable properties from an unknown value, recursively processing objects and arrays\n */\nfunction retainSerializableProps(maybeSerializable: unknown, depth = 0): SerializableProp {\n if (depth > MAX_CUSTOM_PROPERTY_DEPTH) {\n return undefined\n }\n\n if (!isDefined(maybeSerializable)) {\n return undefined\n }\n\n if (isPrimitive(maybeSerializable)) {\n // cull empty strings\n if (maybeSerializable === '') {\n return undefined\n }\n return maybeSerializable\n }\n\n // url-schemes ect..\n if (maybeSerializable instanceof RegExp) {\n return maybeSerializable.toString()\n }\n\n if (Array.isArray(maybeSerializable)) {\n const arrayItems = maybeSerializable\n .map((item) => retainSerializableProps(item, depth + 1))\n .filter((item): item is ManifestSerializable => isDefined(item))\n return arrayItems.length > 0 ? arrayItems : undefined\n }\n\n if (isRecord(maybeSerializable)) {\n const serializableEntries = Object.entries(maybeSerializable)\n .map(([key, value]) => {\n return [key, retainSerializableProps(value, depth + 1)]\n })\n .filter(([, value]) => isDefined(value))\n return serializableEntries.length > 0 ? Object.fromEntries(serializableEntries) : undefined\n }\n\n return undefined\n}\n\n/**\n * Transforms an ObjectField to its manifest representation\n */\nfunction transformField(field: ObjectField & {fieldset?: string}, context: Context): ManifestField {\n const fieldType = field.type\n const typeName = getDefinedTypeName(fieldType) ?? fieldType.name\n return {\n ...transformCommonTypeFields(fieldType, typeName, context),\n name: field.name,\n type: typeName,\n ...ensureCustomTitle(field.name, fieldType.title),\n // this prop gets added synthetically via getCustomFields\n ...ensureString('fieldset', field.fieldset),\n }\n}\n\n/**\n * Transforms array member types to their manifest representation\n */\nfunction transformArrayMember(\n arrayMember: ArraySchemaType,\n context: Context,\n): Pick<ManifestField, 'of'> {\n return {\n of: arrayMember.of.map((type) => {\n const typeName = getDefinedTypeName(type) ?? type.name\n return {\n ...transformCommonTypeFields(type, typeName, context),\n type: typeName,\n ...(typeName === type.name ? {} : {name: type.name}),\n ...ensureCustomTitle(type.name, type.title),\n }\n }),\n }\n}\n"],"names":["transformBlockType","transformCrossDatasetReference","transformGlobalDocumentReference","transformReference","getCustomFields","getDefinedTypeName","isCrossDatasetReference","isCustomized","isDefined","isGlobalDocumentReference","isPrimitive","isRecord","isReference","ensureConditional","ensureCustomTitle","ensureString","transformValidation","MAX_CUSTOM_PROPERTY_DEPTH","transformType","type","context","typeName","name","jsonType","transformCommonTypeFields","title","arrayProps","transformArrayMember","referenceProps","retainCustomTypeProps","crossDatasetRefProps","globalRefProps","objectFields","fields","map","objectField","transformField","validation","retainSerializableProps","description","readOnly","hidden","transformFieldsets","fieldset","fieldsets","filter","fs","single","options","length","manuallySerializedFields","Set","typeWithoutManuallyHandledFields","Object","fromEntries","entries","key","has","maybeSerializable","depth","undefined","RegExp","toString","Array","isArray","arrayItems","item","serializableEntries","value","field","fieldType","arrayMember","of"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/manifest/schemaTypeTransformer.ts"],"sourcesContent":["import {\n type ArraySchemaType,\n type BlockDefinition,\n type BooleanSchemaType,\n type FileSchemaType,\n type MultiFieldSet,\n type NumberSchemaType,\n type ObjectField,\n type ObjectSchemaType,\n type ReferenceSchemaType,\n type SchemaType,\n type StringSchemaType,\n} from '@sanity/types'\n\nimport {transformBlockType} from './blockTypeTransformer.js'\nimport {\n transformCrossDatasetReference,\n transformGlobalDocumentReference,\n transformReference,\n} from './referenceTransformer.js'\nimport {\n getCustomFields,\n getDefinedTypeName,\n isCrossDatasetReference,\n isCustomized,\n isDefined,\n isGlobalDocumentReference,\n isPrimitive,\n isRecord,\n isReference,\n} from './schemaTypeHelpers.js'\nimport {\n type Context,\n ensureConditional,\n ensureCustomTitle,\n ensureString,\n type SerializableProp,\n} from './transformerUtils.js'\nimport {\n type ManifestField,\n type ManifestFieldset,\n type ManifestSchemaType,\n type ManifestSerializable,\n} from './types.js'\nimport {transformValidation} from './validationTransformer.js'\n\ntype SchemaTypeKey =\n | 'group' // we strip this from fields\n | keyof ArraySchemaType\n | keyof BlockDefinition\n | keyof BooleanSchemaType\n | keyof FileSchemaType\n | keyof NumberSchemaType\n | keyof ObjectSchemaType\n | keyof ReferenceSchemaType\n | keyof StringSchemaType\n\ntype ObjectFields = Record<string, never> | {fields: ManifestField[]}\n\nconst MAX_CUSTOM_PROPERTY_DEPTH = 5\n\n/**\n * Transforms a SchemaType to its manifest representation\n */\nexport function transformType(type: SchemaType, context: Context): ManifestSchemaType {\n const typeName = type.type ? type.type.name : type.jsonType\n\n return {\n ...transformCommonTypeFields(type, typeName, context),\n name: type.name,\n type: typeName,\n ...ensureCustomTitle(type.name, type.title),\n }\n}\n\n/**\n * Transforms common fields shared across all schema types\n */\nfunction transformCommonTypeFields(\n type: SchemaType & {fieldset?: string},\n typeName: string,\n context: Context,\n): Omit<ManifestSchemaType, 'name' | 'title' | 'type'> {\n const arrayProps =\n typeName === 'array' && type.jsonType === 'array' ? transformArrayMember(type, context) : {}\n\n const referenceProps = isReference(type) ? transformReference(type, retainCustomTypeProps) : {}\n const crossDatasetRefProps = isCrossDatasetReference(type)\n ? transformCrossDatasetReference(type)\n : {}\n const globalRefProps = isGlobalDocumentReference(type)\n ? transformGlobalDocumentReference(type)\n : {}\n\n const objectFields: ObjectFields =\n type.jsonType === 'object' && type.type && isCustomized(type)\n ? {\n fields: getCustomFields(type).map((objectField) => transformField(objectField, context)),\n }\n : {}\n\n return {\n ...retainCustomTypeProps(type),\n ...transformValidation(type.validation, retainSerializableProps),\n ...ensureString('description', type.description),\n ...objectFields,\n ...arrayProps,\n ...referenceProps,\n ...crossDatasetRefProps,\n ...globalRefProps,\n ...ensureConditional('readOnly', type.readOnly),\n ...ensureConditional('hidden', type.hidden),\n ...transformFieldsets(type),\n // fieldset prop gets instrumented via getCustomFields\n ...ensureString('fieldset', type.fieldset),\n ...transformBlockType(type, context, transformType),\n }\n}\n\n/**\n * Transforms fieldsets from a schema type\n */\nfunction transformFieldsets(\n type: SchemaType,\n): Record<string, never> | {fieldsets: ManifestFieldset[]} {\n if (type.jsonType !== 'object') {\n return {}\n }\n const fieldsets = type.fieldsets\n ?.filter((fs): fs is MultiFieldSet => !fs.single)\n .map((fs) => {\n const options = isRecord(fs.options) ? {options: retainSerializableProps(fs.options)} : {}\n return {\n name: fs.name,\n ...ensureCustomTitle(fs.name, fs.title),\n ...ensureString('description', fs.description),\n ...ensureConditional('readOnly', fs.readOnly),\n ...ensureConditional('hidden', fs.hidden),\n ...options,\n }\n })\n\n return fieldsets?.length ? {fieldsets} : {}\n}\n\n/**\n * Retains custom type properties that should be included in the manifest\n */\nfunction retainCustomTypeProps(type: SchemaType): Record<string, SerializableProp> {\n const manuallySerializedFields = new Set<SchemaTypeKey>([\n '__experimental_actions',\n '__experimental_formPreviewTitle',\n '__experimental_omnisearch_visibility',\n '__experimental_search',\n 'components',\n 'description',\n 'fields',\n 'fieldsets',\n //only exists on fields\n 'group',\n 'groups',\n 'hidden',\n 'icon',\n 'jsonType',\n //explicitly added\n 'name',\n 'of',\n 'orderings',\n 'preview',\n 'readOnly',\n 'title',\n 'to',\n // not serialized\n 'type',\n 'validation',\n // we know about these, but let them be generically handled\n // deprecated\n // rows (from text)\n // initialValue\n // options\n // crossDatasetReference props\n ])\n const typeWithoutManuallyHandledFields = Object.fromEntries(\n Object.entries(type).filter(\n ([key]) => !manuallySerializedFields.has(key as unknown as SchemaTypeKey),\n ),\n )\n return retainSerializableProps(typeWithoutManuallyHandledFields) as Record<\n string,\n SerializableProp\n >\n}\n\n/**\n * Retains serializable properties from an unknown value, recursively processing objects and arrays\n * @internal Exported for testing purposes only\n */\nexport function retainSerializableProps(maybeSerializable: unknown, depth = 0): SerializableProp {\n if (depth > MAX_CUSTOM_PROPERTY_DEPTH) {\n return undefined\n }\n\n if (!isDefined(maybeSerializable)) {\n return undefined\n }\n\n if (isPrimitive(maybeSerializable)) {\n // cull empty strings\n if (maybeSerializable === '') {\n return undefined\n }\n return maybeSerializable\n }\n\n // url-schemes ect..\n if (maybeSerializable instanceof RegExp) {\n return maybeSerializable.toString()\n }\n\n if (Array.isArray(maybeSerializable)) {\n const arrayItems = maybeSerializable\n .map((item) => retainSerializableProps(item, depth + 1))\n .filter((item): item is ManifestSerializable => isDefined(item))\n return arrayItems.length > 0 ? arrayItems : undefined\n }\n\n if (isRecord(maybeSerializable)) {\n const serializableEntries = Object.entries(maybeSerializable)\n .map(([key, value]) => {\n return [key, retainSerializableProps(value, depth + 1)]\n })\n .filter(([, value]) => isDefined(value))\n return serializableEntries.length > 0 ? Object.fromEntries(serializableEntries) : undefined\n }\n\n return undefined\n}\n\n/**\n * Transforms an ObjectField to its manifest representation\n */\nfunction transformField(field: ObjectField & {fieldset?: string}, context: Context): ManifestField {\n const fieldType = field.type\n const typeName = getDefinedTypeName(fieldType) ?? fieldType.name\n return {\n ...transformCommonTypeFields(fieldType, typeName, context),\n name: field.name,\n type: typeName,\n ...ensureCustomTitle(field.name, fieldType.title),\n // this prop gets added synthetically via getCustomFields\n ...ensureString('fieldset', field.fieldset),\n }\n}\n\n/**\n * Transforms array member types to their manifest representation\n */\nfunction transformArrayMember(\n arrayMember: ArraySchemaType,\n context: Context,\n): Pick<ManifestField, 'of'> {\n return {\n of: arrayMember.of.map((type) => {\n const typeName = getDefinedTypeName(type) ?? type.name\n return {\n ...transformCommonTypeFields(type, typeName, context),\n type: typeName,\n ...(typeName === type.name ? {} : {name: type.name}),\n ...ensureCustomTitle(type.name, type.title),\n }\n }),\n }\n}\n"],"names":["transformBlockType","transformCrossDatasetReference","transformGlobalDocumentReference","transformReference","getCustomFields","getDefinedTypeName","isCrossDatasetReference","isCustomized","isDefined","isGlobalDocumentReference","isPrimitive","isRecord","isReference","ensureConditional","ensureCustomTitle","ensureString","transformValidation","MAX_CUSTOM_PROPERTY_DEPTH","transformType","type","context","typeName","name","jsonType","transformCommonTypeFields","title","arrayProps","transformArrayMember","referenceProps","retainCustomTypeProps","crossDatasetRefProps","globalRefProps","objectFields","fields","map","objectField","transformField","validation","retainSerializableProps","description","readOnly","hidden","transformFieldsets","fieldset","fieldsets","filter","fs","single","options","length","manuallySerializedFields","Set","typeWithoutManuallyHandledFields","Object","fromEntries","entries","key","has","maybeSerializable","depth","undefined","RegExp","toString","Array","isArray","arrayItems","item","serializableEntries","value","field","fieldType","arrayMember","of"],"mappings":"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"}
|
|
@@ -59,16 +59,20 @@ export class ImportDatasetCommand extends SanityCommand {
|
|
|
59
59
|
static description = 'Import documents to a Sanity dataset';
|
|
60
60
|
static examples = [
|
|
61
61
|
{
|
|
62
|
-
command: '<%= config.bin %> <%= command.id %> -d staging
|
|
62
|
+
command: '<%= config.bin %> <%= command.id %> -d staging my-dataset.ndjson',
|
|
63
63
|
description: 'Import "./my-dataset.ndjson" into dataset "staging"'
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
|
-
command: 'cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -
|
|
66
|
+
command: 'cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -',
|
|
67
67
|
description: 'Import into dataset "test" from stdin'
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
|
-
command: '<%= config.bin %> <%= command.id %> -p projectId -d staging
|
|
70
|
+
command: '<%= config.bin %> <%= command.id %> -p projectId -d staging my-dataset.ndjson',
|
|
71
71
|
description: 'Import with explicit project ID (overrides CLI configuration)'
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
command: '<%= config.bin %> <%= command.id %> -d staging -t someSecretToken my-dataset.ndjson',
|
|
75
|
+
description: 'Import with an explicit token (e.g. for CI/CD)'
|
|
72
76
|
}
|
|
73
77
|
];
|
|
74
78
|
static flags = {
|
|
@@ -165,12 +169,6 @@ export class ImportDatasetCommand extends SanityCommand {
|
|
|
165
169
|
exit: 1
|
|
166
170
|
});
|
|
167
171
|
}
|
|
168
|
-
const tokenString = token;
|
|
169
|
-
if (!tokenString) {
|
|
170
|
-
this.error('Flag `--token` is required (or set SANITY_IMPORT_TOKEN)', {
|
|
171
|
-
exit: 1
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
172
|
let operation = 'create';
|
|
175
173
|
let releasesOperation = 'fail';
|
|
176
174
|
if (replace || missing) {
|
|
@@ -181,7 +179,10 @@ export class ImportDatasetCommand extends SanityCommand {
|
|
|
181
179
|
apiVersion: 'v2025-02-19',
|
|
182
180
|
dataset,
|
|
183
181
|
projectId,
|
|
184
|
-
|
|
182
|
+
requireUser: true,
|
|
183
|
+
...token ? {
|
|
184
|
+
token
|
|
185
|
+
} : {}
|
|
185
186
|
});
|
|
186
187
|
try {
|
|
187
188
|
const stream = await ImportDatasetCommand.getStream(source);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/datasets/import.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {Args, Flags} from '@oclif/core'\nimport {getProjectCliClient, SanityCommand} from '@sanity/cli-core'\nimport {createRequester} from '@sanity/cli-core/request'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {sanityImport} from '@sanity/import'\nimport prettyMs from 'pretty-ms'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getDatasetFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\ninterface ProgressEvent {\n step: string\n\n current?: number\n total?: number\n update?: string\n}\n\nfunction getAssetsBase(source: string): string | undefined {\n if (/^https?:\\/\\//i.test(source) || source === '-') {\n return undefined\n }\n\n try {\n const fileStats = fs.statSync(source)\n const sourceIsFolder = fileStats.isDirectory()\n return sourceIsFolder ? source : path.dirname(source)\n } catch {\n return undefined\n }\n}\n\nasync function getUriStream(uri: string): Promise<NodeJS.ReadableStream> {\n const request = createRequester({\n middleware: {promise: {onlyBody: false}},\n })\n\n try {\n const response = (await request({stream: true, url: uri})) as {body: NodeJS.ReadableStream}\n return response.body\n } catch (err) {\n throw new Error(`Error fetching source:\\n${(err as Error).message}`)\n }\n}\n\nfunction getPercentage(opts: ProgressEvent): string {\n if (!opts.total) {\n return ''\n }\n\n const percent = Math.floor(((opts.current || 0) / opts.total) * 100)\n return `[${percent}%] `\n}\n\nexport class ImportDatasetCommand extends SanityCommand<typeof ImportDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Source file (use \"-\" for stdin)',\n required: true,\n }),\n targetDataset: Args.string({\n description: 'Target dataset (prefer --dataset flag instead)',\n required: false,\n }),\n }\n\n static override description = 'Import documents to a Sanity dataset'\n\n static override examples = [\n {\n command:\n '<%= config.bin %> <%= command.id %> -d staging -t someSecretToken my-dataset.ndjson',\n description: 'Import \"./my-dataset.ndjson\" into dataset \"staging\"',\n },\n {\n command: 'cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -t someToken -',\n description: 'Import into dataset \"test\" from stdin',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> -p projectId -d staging -t someSecretToken my-dataset.ndjson',\n description: 'Import with explicit project ID (overrides CLI configuration)',\n },\n ]\n\n static override flags = {\n 'allow-assets-in-different-dataset': Flags.boolean({\n default: false,\n description: 'Allow asset documents to reference different project/dataset',\n }),\n 'allow-failing-assets': Flags.boolean({\n default: false,\n description: 'Skip assets that cannot be fetched/uploaded',\n }),\n 'allow-replacement-characters': Flags.boolean({\n default: false,\n description: 'Allow unicode replacement characters in imported documents',\n }),\n 'allow-system-documents': Flags.boolean({\n default: false,\n description: 'Imports system documents',\n }),\n 'asset-concurrency': Flags.integer({\n description: 'Number of parallel asset imports',\n }),\n ...getDatasetFlag({\n description: 'Dataset to import to',\n semantics: 'specify',\n }),\n missing: Flags.boolean({\n default: false,\n description: 'Skip documents that already exist',\n exclusive: ['replace'],\n }),\n ...getProjectIdFlag({\n description: 'Project ID to import to',\n semantics: 'override',\n }),\n project: Flags.string({\n deprecated: {to: 'project-id'},\n description: 'Project ID to import to',\n hidden: true,\n }),\n replace: Flags.boolean({\n default: false,\n description: 'Replace documents with the same IDs',\n exclusive: ['missing'],\n }),\n 'replace-assets': Flags.boolean({\n default: false,\n description: 'Skip reuse of existing assets',\n }),\n 'skip-cross-dataset-references': Flags.boolean({\n default: false,\n description: 'Skips references to other datasets',\n }),\n token: Flags.string({\n char: 't',\n description: 'Token to authenticate with',\n env: 'SANITY_IMPORT_TOKEN',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:import']\n\n private currentProgress?: ReturnType<typeof spinner>\n private currentStep?: string\n private spinInterval?: NodeJS.Timeout | null\n private stepStart?: number\n\n private static async getStream(source: string): Promise<NodeJS.ReadableStream> {\n if (/^https?:\\/\\//i.test(source)) {\n return getUriStream(source)\n }\n\n return source === '-' ? process.stdin : fs.createReadStream(source)\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ImportDatasetCommand)\n\n const {\n 'allow-assets-in-different-dataset': allowAssetsInDifferentDataset,\n 'allow-failing-assets': allowFailingAssets,\n 'allow-replacement-characters': allowReplacementCharacters,\n 'allow-system-documents': allowSystemDocuments,\n 'asset-concurrency': assetConcurrency,\n dataset: datasetFlag,\n missing,\n replace,\n 'replace-assets': replaceAssets,\n 'skip-cross-dataset-references': skipCrossDatasetReferences,\n token,\n } = flags\n\n const projectId = await this.getProjectId({\n deprecatedFlagName: 'project',\n fallback: () => promptForProject({}),\n })\n\n const {source, targetDataset: targetDatasetArg} = args\n\n if (targetDatasetArg && !datasetFlag) {\n this.warn(\n 'Positional dataset argument is deprecated. Use the --dataset flag instead: --dataset <name>',\n )\n }\n\n const dataset = datasetFlag ?? targetDatasetArg\n if (!dataset) {\n this.error('Missing dataset. Use the --dataset flag to specify a dataset: --dataset <name>', {\n exit: 1,\n })\n }\n\n const tokenString: string | undefined = token\n if (!tokenString) {\n this.error('Flag `--token` is required (or set SANITY_IMPORT_TOKEN)', {exit: 1})\n }\n\n let operation: 'create' | 'createIfNotExists' | 'createOrReplace' = 'create'\n let releasesOperation: 'fail' | 'ignore' | 'replace' = 'fail'\n\n if (replace || missing) {\n operation = replace ? 'createOrReplace' : 'createIfNotExists'\n releasesOperation = replace ? 'replace' : 'ignore'\n }\n\n const client = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n dataset,\n projectId,\n token: tokenString,\n })\n\n try {\n const stream = await ImportDatasetCommand.getStream(source)\n const assetsBase = getAssetsBase(source)\n\n const importOptions = {\n allowAssetsInDifferentDataset,\n allowFailingAssets,\n allowReplacementCharacters,\n allowSystemDocuments,\n client,\n onProgress: this.onProgress.bind(this),\n operation,\n releasesOperation,\n replaceAssets,\n skipCrossDatasetReferences,\n tag: 'sanity.import',\n targetDataset: dataset,\n targetProjectId: projectId,\n ...(assetsBase ? {assetsBase} : {}),\n ...(assetConcurrency === undefined ? {} : {assetConcurrency}),\n }\n\n const {numDocs, warnings} = await sanityImport(stream as NodeJS.ReadableStream, importOptions)\n\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n this.currentProgress.text = `[100%] ${this.currentStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n }\n\n this.log('Done! Imported %d documents to dataset \"%s\"\\n', numDocs, dataset)\n this.printWarnings(warnings)\n } catch (err) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress) {\n this.currentProgress.fail()\n }\n\n if ((err as Error).name === 'ReplacementCharError') {\n this.error(\n `Import failed due to unicode replacement characters in the data.\\n${(err as Error).message}\\n\\nIf you are certain you want to proceed with the import despite potentially corrupt data, re-run the import with the \\`--allow-replacement-characters\\` flag set.`,\n {exit: 1},\n )\n } else {\n this.error((err as Error).stack || (err as Error).message, {exit: 1})\n }\n }\n }\n\n private onProgress(opts: ProgressEvent): void {\n const lengthComputable = opts.total\n const sameStep = opts.step === this.currentStep\n const percent = getPercentage(opts)\n\n if (lengthComputable && opts.total === opts.current && this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (sameStep && !lengthComputable) {\n return\n }\n\n if (sameStep) {\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }\n return\n }\n\n // Moved to a new step\n const prevStep = this.currentStep\n const prevStepStart = this.stepStart\n this.stepStart = Date.now()\n this.currentStep = opts.step\n\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress && this.currentProgress.succeed && prevStepStart) {\n const timeSpent = prettyMs(Date.now() - prevStepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `[100%] ${prevStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n\n this.currentProgress = spinner(`[0%] ${opts.step} (0.00s)`).start()\n\n if (!lengthComputable) {\n this.spinInterval = setInterval(() => {\n if (this.stepStart && this.currentProgress) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }, 60)\n }\n }\n\n private printWarnings(warnings: Array<{message: string; type?: string; url?: string}>): void {\n const assetFails = warnings.filter((warn) => warn.type === 'asset')\n\n if (assetFails.length === 0) {\n return\n }\n\n this.warn(`Failed to import the following ${assetFails.length > 1 ? 'assets' : 'asset'}:`)\n\n for (const warning of assetFails) {\n if (warning.url) {\n this.warn(` ${warning.url}`)\n }\n }\n }\n}\n"],"names":["fs","path","Args","Flags","getProjectCliClient","SanityCommand","createRequester","spinner","sanityImport","prettyMs","promptForProject","getDatasetFlag","getProjectIdFlag","getAssetsBase","source","test","undefined","fileStats","statSync","sourceIsFolder","isDirectory","dirname","getUriStream","uri","request","middleware","promise","onlyBody","response","stream","url","body","err","Error","message","getPercentage","opts","total","percent","Math","floor","current","ImportDatasetCommand","args","string","description","required","targetDataset","examples","command","flags","boolean","default","integer","semantics","missing","exclusive","project","deprecated","to","hidden","replace","token","char","env","hiddenAliases","currentProgress","currentStep","spinInterval","stepStart","getStream","process","stdin","createReadStream","run","parse","allowAssetsInDifferentDataset","allowFailingAssets","allowReplacementCharacters","allowSystemDocuments","assetConcurrency","dataset","datasetFlag","replaceAssets","skipCrossDatasetReferences","projectId","getProjectId","deprecatedFlagName","fallback","targetDatasetArg","warn","error","exit","tokenString","operation","releasesOperation","client","apiVersion","assetsBase","importOptions","onProgress","bind","tag","targetProjectId","numDocs","warnings","timeSpent","Date","now","secondsDecimalDigits","clearInterval","text","succeed","log","printWarnings","fail","name","stack","lengthComputable","sameStep","step","render","prevStep","prevStepStart","start","setInterval","assetFails","filter","type","length","warning"],"mappings":"AAAA,OAAOA,QAAQ,UAAS;AACxB,OAAOC,UAAU,YAAW;AAE5B,SAAQC,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,mBAAmB,EAAEC,aAAa,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,2BAA0B;AACxD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,YAAY,QAAO,iBAAgB;AAC3C,OAAOC,cAAc,YAAW;AAEhC,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,cAAc,EAAEC,gBAAgB,QAAO,4BAA2B;AAU1E,SAASC,cAAcC,MAAc;IACnC,IAAI,gBAAgBC,IAAI,CAACD,WAAWA,WAAW,KAAK;QAClD,OAAOE;IACT;IAEA,IAAI;QACF,MAAMC,YAAYjB,GAAGkB,QAAQ,CAACJ;QAC9B,MAAMK,iBAAiBF,UAAUG,WAAW;QAC5C,OAAOD,iBAAiBL,SAASb,KAAKoB,OAAO,CAACP;IAChD,EAAE,OAAM;QACN,OAAOE;IACT;AACF;AAEA,eAAeM,aAAaC,GAAW;IACrC,MAAMC,UAAUlB,gBAAgB;QAC9BmB,YAAY;YAACC,SAAS;gBAACC,UAAU;YAAK;QAAC;IACzC;IAEA,IAAI;QACF,MAAMC,WAAY,MAAMJ,QAAQ;YAACK,QAAQ;YAAMC,KAAKP;QAAG;QACvD,OAAOK,SAASG,IAAI;IACtB,EAAE,OAAOC,KAAK;QACZ,MAAM,IAAIC,MAAM,CAAC,wBAAwB,EAAE,AAACD,IAAcE,OAAO,EAAE;IACrE;AACF;AAEA,SAASC,cAAcC,IAAmB;IACxC,IAAI,CAACA,KAAKC,KAAK,EAAE;QACf,OAAO;IACT;IAEA,MAAMC,UAAUC,KAAKC,KAAK,CAAC,AAAEJ,CAAAA,KAAKK,OAAO,IAAI,CAAA,IAAKL,KAAKC,KAAK,GAAI;IAChE,OAAO,CAAC,CAAC,EAAEC,QAAQ,GAAG,CAAC;AACzB;AAEA,OAAO,MAAMI,6BAA6BrC;IACxC,OAAgBsC,OAAO;QACrB7B,QAAQZ,KAAK0C,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;QACAC,eAAe7C,KAAK0C,MAAM,CAAC;YACzBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,uCAAsC;IAEpE,OAAgBG,WAAW;QACzB;YACEC,SACE;YACFJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SACE;YACFJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtB,qCAAqC/C,MAAMgD,OAAO,CAAC;YACjDC,SAAS;YACTP,aAAa;QACf;QACA,wBAAwB1C,MAAMgD,OAAO,CAAC;YACpCC,SAAS;YACTP,aAAa;QACf;QACA,gCAAgC1C,MAAMgD,OAAO,CAAC;YAC5CC,SAAS;YACTP,aAAa;QACf;QACA,0BAA0B1C,MAAMgD,OAAO,CAAC;YACtCC,SAAS;YACTP,aAAa;QACf;QACA,qBAAqB1C,MAAMkD,OAAO,CAAC;YACjCR,aAAa;QACf;QACA,GAAGlC,eAAe;YAChBkC,aAAa;YACbS,WAAW;QACb,EAAE;QACFC,SAASpD,MAAMgD,OAAO,CAAC;YACrBC,SAAS;YACTP,aAAa;YACbW,WAAW;gBAAC;aAAU;QACxB;QACA,GAAG5C,iBAAiB;YAClBiC,aAAa;YACbS,WAAW;QACb,EAAE;QACFG,SAAStD,MAAMyC,MAAM,CAAC;YACpBc,YAAY;gBAACC,IAAI;YAAY;YAC7Bd,aAAa;YACbe,QAAQ;QACV;QACAC,SAAS1D,MAAMgD,OAAO,CAAC;YACrBC,SAAS;YACTP,aAAa;YACbW,WAAW;gBAAC;aAAU;QACxB;QACA,kBAAkBrD,MAAMgD,OAAO,CAAC;YAC9BC,SAAS;YACTP,aAAa;QACf;QACA,iCAAiC1C,MAAMgD,OAAO,CAAC;YAC7CC,SAAS;YACTP,aAAa;QACf;QACAiB,OAAO3D,MAAMyC,MAAM,CAAC;YAClBmB,MAAM;YACNlB,aAAa;YACbmB,KAAK;YACLlB,UAAU;QACZ;IACF,EAAC;IAED,OAAgBmB,gBAA0B;QAAC;KAAiB,CAAA;IAEpDC,gBAA4C;IAC5CC,YAAoB;IACpBC,aAAoC;IACpCC,UAAkB;IAE1B,aAAqBC,UAAUxD,MAAc,EAAkC;QAC7E,IAAI,gBAAgBC,IAAI,CAACD,SAAS;YAChC,OAAOQ,aAAaR;QACtB;QAEA,OAAOA,WAAW,MAAMyD,QAAQC,KAAK,GAAGxE,GAAGyE,gBAAgB,CAAC3D;IAC9D;IAEA,MAAa4D,MAAqB;QAChC,MAAM,EAAC/B,IAAI,EAAEO,KAAK,EAAC,GAAG,MAAM,IAAI,CAACyB,KAAK,CAACjC;QAEvC,MAAM,EACJ,qCAAqCkC,6BAA6B,EAClE,wBAAwBC,kBAAkB,EAC1C,gCAAgCC,0BAA0B,EAC1D,0BAA0BC,oBAAoB,EAC9C,qBAAqBC,gBAAgB,EACrCC,SAASC,WAAW,EACpB3B,OAAO,EACPM,OAAO,EACP,kBAAkBsB,aAAa,EAC/B,iCAAiCC,0BAA0B,EAC3DtB,KAAK,EACN,GAAGZ;QAEJ,MAAMmC,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,oBAAoB;YACpBC,UAAU,IAAM9E,iBAAiB,CAAC;QACpC;QAEA,MAAM,EAACI,MAAM,EAAEiC,eAAe0C,gBAAgB,EAAC,GAAG9C;QAElD,IAAI8C,oBAAoB,CAACP,aAAa;YACpC,IAAI,CAACQ,IAAI,CACP;QAEJ;QAEA,MAAMT,UAAUC,eAAeO;QAC/B,IAAI,CAACR,SAAS;YACZ,IAAI,CAACU,KAAK,CAAC,kFAAkF;gBAC3FC,MAAM;YACR;QACF;QAEA,MAAMC,cAAkC/B;QACxC,IAAI,CAAC+B,aAAa;YAChB,IAAI,CAACF,KAAK,CAAC,2DAA2D;gBAACC,MAAM;YAAC;QAChF;QAEA,IAAIE,YAAgE;QACpE,IAAIC,oBAAmD;QAEvD,IAAIlC,WAAWN,SAAS;YACtBuC,YAAYjC,UAAU,oBAAoB;YAC1CkC,oBAAoBlC,UAAU,YAAY;QAC5C;QAEA,MAAMmC,SAAS,MAAM5F,oBAAoB;YACvC6F,YAAY;YACZhB;YACAI;YACAvB,OAAO+B;QACT;QAEA,IAAI;YACF,MAAMhE,SAAS,MAAMa,qBAAqB4B,SAAS,CAACxD;YACpD,MAAMoF,aAAarF,cAAcC;YAEjC,MAAMqF,gBAAgB;gBACpBvB;gBACAC;gBACAC;gBACAC;gBACAiB;gBACAI,YAAY,IAAI,CAACA,UAAU,CAACC,IAAI,CAAC,IAAI;gBACrCP;gBACAC;gBACAZ;gBACAC;gBACAkB,KAAK;gBACLvD,eAAekC;gBACfsB,iBAAiBlB;gBACjB,GAAIa,aAAa;oBAACA;gBAAU,IAAI,CAAC,CAAC;gBAClC,GAAIlB,qBAAqBhE,YAAY,CAAC,IAAI;oBAACgE;gBAAgB,CAAC;YAC9D;YAEA,MAAM,EAACwB,OAAO,EAAEC,QAAQ,EAAC,GAAG,MAAMjG,aAAaqB,QAAiCsE;YAEhF,IAAI,IAAI,CAAC9B,SAAS,EAAE;gBAClB,MAAMqC,YAAYjG,SAASkG,KAAKC,GAAG,KAAK,IAAI,CAACvC,SAAS,EAAE;oBAACwC,sBAAsB;gBAAC;gBAChF,IAAI,IAAI,CAAC3C,eAAe,EAAE;oBACxB,IAAI,IAAI,CAACE,YAAY,EAAE;wBACrB0C,cAAc,IAAI,CAAC1C,YAAY;wBAC/B,IAAI,CAACA,YAAY,GAAG;oBACtB;oBACA,IAAI,CAACF,eAAe,CAAC6C,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC5C,WAAW,CAAC,EAAE,EAAEuC,UAAU,CAAC,CAAC;oBACvE,IAAI,CAACxC,eAAe,CAAC8C,OAAO;gBAC9B;YACF;YAEA,IAAI,CAACC,GAAG,CAAC,iDAAiDT,SAASvB;YACnE,IAAI,CAACiC,aAAa,CAACT;QACrB,EAAE,OAAOzE,KAAK;YACZ,IAAI,IAAI,CAACoC,YAAY,EAAE;gBACrB0C,cAAc,IAAI,CAAC1C,YAAY;gBAC/B,IAAI,CAACA,YAAY,GAAG;YACtB;YAEA,IAAI,IAAI,CAACF,eAAe,EAAE;gBACxB,IAAI,CAACA,eAAe,CAACiD,IAAI;YAC3B;YAEA,IAAI,AAACnF,IAAcoF,IAAI,KAAK,wBAAwB;gBAClD,IAAI,CAACzB,KAAK,CACR,CAAC,kEAAkE,EAAE,AAAC3D,IAAcE,OAAO,CAAC,oKAAoK,CAAC,EACjQ;oBAAC0D,MAAM;gBAAC;YAEZ,OAAO;gBACL,IAAI,CAACD,KAAK,CAAC,AAAC3D,IAAcqF,KAAK,IAAI,AAACrF,IAAcE,OAAO,EAAE;oBAAC0D,MAAM;gBAAC;YACrE;QACF;IACF;IAEQQ,WAAWhE,IAAmB,EAAQ;QAC5C,MAAMkF,mBAAmBlF,KAAKC,KAAK;QACnC,MAAMkF,WAAWnF,KAAKoF,IAAI,KAAK,IAAI,CAACrD,WAAW;QAC/C,MAAM7B,UAAUH,cAAcC;QAE9B,IAAIkF,oBAAoBlF,KAAKC,KAAK,KAAKD,KAAKK,OAAO,IAAI,IAAI,CAAC2B,YAAY,EAAE;YACxE0C,cAAc,IAAI,CAAC1C,YAAY;YAC/B,IAAI,CAACA,YAAY,GAAG;QACtB;QAEA,IAAImD,YAAY,CAACD,kBAAkB;YACjC;QACF;QAEA,IAAIC,UAAU;YACZ,IAAI,IAAI,CAAClD,SAAS,EAAE;gBAClB,MAAMqC,YAAYjG,SAASkG,KAAKC,GAAG,KAAK,IAAI,CAACvC,SAAS,EAAE;oBAACwC,sBAAsB;gBAAC;gBAChF,IAAI,IAAI,CAAC3C,eAAe,EAAE;oBACxB,IAAI,CAACA,eAAe,CAAC6C,IAAI,GAAG,GAAGzE,UAAUF,KAAKoF,IAAI,CAAC,EAAE,EAAEd,UAAU,CAAC,CAAC;oBACnE,IAAI,CAACxC,eAAe,CAACuD,MAAM;gBAC7B;YACF;YACA;QACF;QAEA,sBAAsB;QACtB,MAAMC,WAAW,IAAI,CAACvD,WAAW;QACjC,MAAMwD,gBAAgB,IAAI,CAACtD,SAAS;QACpC,IAAI,CAACA,SAAS,GAAGsC,KAAKC,GAAG;QACzB,IAAI,CAACzC,WAAW,GAAG/B,KAAKoF,IAAI;QAE5B,IAAI,IAAI,CAACpD,YAAY,EAAE;YACrB0C,cAAc,IAAI,CAAC1C,YAAY;YAC/B,IAAI,CAACA,YAAY,GAAG;QACtB;QAEA,IAAI,IAAI,CAACF,eAAe,IAAI,IAAI,CAACA,eAAe,CAAC8C,OAAO,IAAIW,eAAe;YACzE,MAAMjB,YAAYjG,SAASkG,KAAKC,GAAG,KAAKe,eAAe;gBACrDd,sBAAsB;YACxB;YACA,IAAI,CAAC3C,eAAe,CAAC6C,IAAI,GAAG,CAAC,OAAO,EAAEW,SAAS,EAAE,EAAEhB,UAAU,CAAC,CAAC;YAC/D,IAAI,CAACxC,eAAe,CAAC8C,OAAO;QAC9B;QAEA,IAAI,CAAC9C,eAAe,GAAG3D,QAAQ,CAAC,KAAK,EAAE6B,KAAKoF,IAAI,CAAC,QAAQ,CAAC,EAAEI,KAAK;QAEjE,IAAI,CAACN,kBAAkB;YACrB,IAAI,CAAClD,YAAY,GAAGyD,YAAY;gBAC9B,IAAI,IAAI,CAACxD,SAAS,IAAI,IAAI,CAACH,eAAe,EAAE;oBAC1C,MAAMwC,YAAYjG,SAASkG,KAAKC,GAAG,KAAK,IAAI,CAACvC,SAAS,EAAE;wBACtDwC,sBAAsB;oBACxB;oBACA,IAAI,CAAC3C,eAAe,CAAC6C,IAAI,GAAG,GAAGzE,UAAUF,KAAKoF,IAAI,CAAC,EAAE,EAAEd,UAAU,CAAC,CAAC;oBACnE,IAAI,CAACxC,eAAe,CAACuD,MAAM;gBAC7B;YACF,GAAG;QACL;IACF;IAEQP,cAAcT,QAA+D,EAAQ;QAC3F,MAAMqB,aAAarB,SAASsB,MAAM,CAAC,CAACrC,OAASA,KAAKsC,IAAI,KAAK;QAE3D,IAAIF,WAAWG,MAAM,KAAK,GAAG;YAC3B;QACF;QAEA,IAAI,CAACvC,IAAI,CAAC,CAAC,+BAA+B,EAAEoC,WAAWG,MAAM,GAAG,IAAI,WAAW,QAAQ,CAAC,CAAC;QAEzF,KAAK,MAAMC,WAAWJ,WAAY;YAChC,IAAII,QAAQpG,GAAG,EAAE;gBACf,IAAI,CAAC4D,IAAI,CAAC,CAAC,EAAE,EAAEwC,QAAQpG,GAAG,EAAE;YAC9B;QACF;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/datasets/import.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {Args, Flags} from '@oclif/core'\nimport {getProjectCliClient, SanityCommand} from '@sanity/cli-core'\nimport {createRequester} from '@sanity/cli-core/request'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {sanityImport} from '@sanity/import'\nimport prettyMs from 'pretty-ms'\n\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getDatasetFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\ninterface ProgressEvent {\n step: string\n\n current?: number\n total?: number\n update?: string\n}\n\nfunction getAssetsBase(source: string): string | undefined {\n if (/^https?:\\/\\//i.test(source) || source === '-') {\n return undefined\n }\n\n try {\n const fileStats = fs.statSync(source)\n const sourceIsFolder = fileStats.isDirectory()\n return sourceIsFolder ? source : path.dirname(source)\n } catch {\n return undefined\n }\n}\n\nasync function getUriStream(uri: string): Promise<NodeJS.ReadableStream> {\n const request = createRequester({\n middleware: {promise: {onlyBody: false}},\n })\n\n try {\n const response = (await request({stream: true, url: uri})) as {body: NodeJS.ReadableStream}\n return response.body\n } catch (err) {\n throw new Error(`Error fetching source:\\n${(err as Error).message}`)\n }\n}\n\nfunction getPercentage(opts: ProgressEvent): string {\n if (!opts.total) {\n return ''\n }\n\n const percent = Math.floor(((opts.current || 0) / opts.total) * 100)\n return `[${percent}%] `\n}\n\nexport class ImportDatasetCommand extends SanityCommand<typeof ImportDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Source file (use \"-\" for stdin)',\n required: true,\n }),\n targetDataset: Args.string({\n description: 'Target dataset (prefer --dataset flag instead)',\n required: false,\n }),\n }\n\n static override description = 'Import documents to a Sanity dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> -d staging my-dataset.ndjson',\n description: 'Import \"./my-dataset.ndjson\" into dataset \"staging\"',\n },\n {\n command: 'cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -',\n description: 'Import into dataset \"test\" from stdin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> -p projectId -d staging my-dataset.ndjson',\n description: 'Import with explicit project ID (overrides CLI configuration)',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> -d staging -t someSecretToken my-dataset.ndjson',\n description: 'Import with an explicit token (e.g. for CI/CD)',\n },\n ]\n\n static override flags = {\n 'allow-assets-in-different-dataset': Flags.boolean({\n default: false,\n description: 'Allow asset documents to reference different project/dataset',\n }),\n 'allow-failing-assets': Flags.boolean({\n default: false,\n description: 'Skip assets that cannot be fetched/uploaded',\n }),\n 'allow-replacement-characters': Flags.boolean({\n default: false,\n description: 'Allow unicode replacement characters in imported documents',\n }),\n 'allow-system-documents': Flags.boolean({\n default: false,\n description: 'Imports system documents',\n }),\n 'asset-concurrency': Flags.integer({\n description: 'Number of parallel asset imports',\n }),\n ...getDatasetFlag({\n description: 'Dataset to import to',\n semantics: 'specify',\n }),\n missing: Flags.boolean({\n default: false,\n description: 'Skip documents that already exist',\n exclusive: ['replace'],\n }),\n ...getProjectIdFlag({\n description: 'Project ID to import to',\n semantics: 'override',\n }),\n project: Flags.string({\n deprecated: {to: 'project-id'},\n description: 'Project ID to import to',\n hidden: true,\n }),\n replace: Flags.boolean({\n default: false,\n description: 'Replace documents with the same IDs',\n exclusive: ['missing'],\n }),\n 'replace-assets': Flags.boolean({\n default: false,\n description: 'Skip reuse of existing assets',\n }),\n 'skip-cross-dataset-references': Flags.boolean({\n default: false,\n description: 'Skips references to other datasets',\n }),\n token: Flags.string({\n char: 't',\n description: 'Token to authenticate with',\n env: 'SANITY_IMPORT_TOKEN',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:import']\n\n private currentProgress?: ReturnType<typeof spinner>\n private currentStep?: string\n private spinInterval?: NodeJS.Timeout | null\n private stepStart?: number\n\n private static async getStream(source: string): Promise<NodeJS.ReadableStream> {\n if (/^https?:\\/\\//i.test(source)) {\n return getUriStream(source)\n }\n\n return source === '-' ? process.stdin : fs.createReadStream(source)\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ImportDatasetCommand)\n\n const {\n 'allow-assets-in-different-dataset': allowAssetsInDifferentDataset,\n 'allow-failing-assets': allowFailingAssets,\n 'allow-replacement-characters': allowReplacementCharacters,\n 'allow-system-documents': allowSystemDocuments,\n 'asset-concurrency': assetConcurrency,\n dataset: datasetFlag,\n missing,\n replace,\n 'replace-assets': replaceAssets,\n 'skip-cross-dataset-references': skipCrossDatasetReferences,\n token,\n } = flags\n\n const projectId = await this.getProjectId({\n deprecatedFlagName: 'project',\n fallback: () => promptForProject({}),\n })\n\n const {source, targetDataset: targetDatasetArg} = args\n\n if (targetDatasetArg && !datasetFlag) {\n this.warn(\n 'Positional dataset argument is deprecated. Use the --dataset flag instead: --dataset <name>',\n )\n }\n\n const dataset = datasetFlag ?? targetDatasetArg\n if (!dataset) {\n this.error('Missing dataset. Use the --dataset flag to specify a dataset: --dataset <name>', {\n exit: 1,\n })\n }\n\n let operation: 'create' | 'createIfNotExists' | 'createOrReplace' = 'create'\n let releasesOperation: 'fail' | 'ignore' | 'replace' = 'fail'\n\n if (replace || missing) {\n operation = replace ? 'createOrReplace' : 'createIfNotExists'\n releasesOperation = replace ? 'replace' : 'ignore'\n }\n\n const client = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n dataset,\n projectId,\n requireUser: true,\n ...(token ? {token} : {}),\n })\n\n try {\n const stream = await ImportDatasetCommand.getStream(source)\n const assetsBase = getAssetsBase(source)\n\n const importOptions = {\n allowAssetsInDifferentDataset,\n allowFailingAssets,\n allowReplacementCharacters,\n allowSystemDocuments,\n client,\n onProgress: this.onProgress.bind(this),\n operation,\n releasesOperation,\n replaceAssets,\n skipCrossDatasetReferences,\n tag: 'sanity.import',\n targetDataset: dataset,\n targetProjectId: projectId,\n ...(assetsBase ? {assetsBase} : {}),\n ...(assetConcurrency === undefined ? {} : {assetConcurrency}),\n }\n\n const {numDocs, warnings} = await sanityImport(stream as NodeJS.ReadableStream, importOptions)\n\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n this.currentProgress.text = `[100%] ${this.currentStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n }\n\n this.log('Done! Imported %d documents to dataset \"%s\"\\n', numDocs, dataset)\n this.printWarnings(warnings)\n } catch (err) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress) {\n this.currentProgress.fail()\n }\n\n if ((err as Error).name === 'ReplacementCharError') {\n this.error(\n `Import failed due to unicode replacement characters in the data.\\n${(err as Error).message}\\n\\nIf you are certain you want to proceed with the import despite potentially corrupt data, re-run the import with the \\`--allow-replacement-characters\\` flag set.`,\n {exit: 1},\n )\n } else {\n this.error((err as Error).stack || (err as Error).message, {exit: 1})\n }\n }\n }\n\n private onProgress(opts: ProgressEvent): void {\n const lengthComputable = opts.total\n const sameStep = opts.step === this.currentStep\n const percent = getPercentage(opts)\n\n if (lengthComputable && opts.total === opts.current && this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (sameStep && !lengthComputable) {\n return\n }\n\n if (sameStep) {\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }\n return\n }\n\n // Moved to a new step\n const prevStep = this.currentStep\n const prevStepStart = this.stepStart\n this.stepStart = Date.now()\n this.currentStep = opts.step\n\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress && this.currentProgress.succeed && prevStepStart) {\n const timeSpent = prettyMs(Date.now() - prevStepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `[100%] ${prevStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n\n this.currentProgress = spinner(`[0%] ${opts.step} (0.00s)`).start()\n\n if (!lengthComputable) {\n this.spinInterval = setInterval(() => {\n if (this.stepStart && this.currentProgress) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }, 60)\n }\n }\n\n private printWarnings(warnings: Array<{message: string; type?: string; url?: string}>): void {\n const assetFails = warnings.filter((warn) => warn.type === 'asset')\n\n if (assetFails.length === 0) {\n return\n }\n\n this.warn(`Failed to import the following ${assetFails.length > 1 ? 'assets' : 'asset'}:`)\n\n for (const warning of assetFails) {\n if (warning.url) {\n this.warn(` ${warning.url}`)\n }\n }\n }\n}\n"],"names":["fs","path","Args","Flags","getProjectCliClient","SanityCommand","createRequester","spinner","sanityImport","prettyMs","promptForProject","getDatasetFlag","getProjectIdFlag","getAssetsBase","source","test","undefined","fileStats","statSync","sourceIsFolder","isDirectory","dirname","getUriStream","uri","request","middleware","promise","onlyBody","response","stream","url","body","err","Error","message","getPercentage","opts","total","percent","Math","floor","current","ImportDatasetCommand","args","string","description","required","targetDataset","examples","command","flags","boolean","default","integer","semantics","missing","exclusive","project","deprecated","to","hidden","replace","token","char","env","hiddenAliases","currentProgress","currentStep","spinInterval","stepStart","getStream","process","stdin","createReadStream","run","parse","allowAssetsInDifferentDataset","allowFailingAssets","allowReplacementCharacters","allowSystemDocuments","assetConcurrency","dataset","datasetFlag","replaceAssets","skipCrossDatasetReferences","projectId","getProjectId","deprecatedFlagName","fallback","targetDatasetArg","warn","error","exit","operation","releasesOperation","client","apiVersion","requireUser","assetsBase","importOptions","onProgress","bind","tag","targetProjectId","numDocs","warnings","timeSpent","Date","now","secondsDecimalDigits","clearInterval","text","succeed","log","printWarnings","fail","name","stack","lengthComputable","sameStep","step","render","prevStep","prevStepStart","start","setInterval","assetFails","filter","type","length","warning"],"mappings":"AAAA,OAAOA,QAAQ,UAAS;AACxB,OAAOC,UAAU,YAAW;AAE5B,SAAQC,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,mBAAmB,EAAEC,aAAa,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,2BAA0B;AACxD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,YAAY,QAAO,iBAAgB;AAC3C,OAAOC,cAAc,YAAW;AAEhC,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,cAAc,EAAEC,gBAAgB,QAAO,4BAA2B;AAU1E,SAASC,cAAcC,MAAc;IACnC,IAAI,gBAAgBC,IAAI,CAACD,WAAWA,WAAW,KAAK;QAClD,OAAOE;IACT;IAEA,IAAI;QACF,MAAMC,YAAYjB,GAAGkB,QAAQ,CAACJ;QAC9B,MAAMK,iBAAiBF,UAAUG,WAAW;QAC5C,OAAOD,iBAAiBL,SAASb,KAAKoB,OAAO,CAACP;IAChD,EAAE,OAAM;QACN,OAAOE;IACT;AACF;AAEA,eAAeM,aAAaC,GAAW;IACrC,MAAMC,UAAUlB,gBAAgB;QAC9BmB,YAAY;YAACC,SAAS;gBAACC,UAAU;YAAK;QAAC;IACzC;IAEA,IAAI;QACF,MAAMC,WAAY,MAAMJ,QAAQ;YAACK,QAAQ;YAAMC,KAAKP;QAAG;QACvD,OAAOK,SAASG,IAAI;IACtB,EAAE,OAAOC,KAAK;QACZ,MAAM,IAAIC,MAAM,CAAC,wBAAwB,EAAE,AAACD,IAAcE,OAAO,EAAE;IACrE;AACF;AAEA,SAASC,cAAcC,IAAmB;IACxC,IAAI,CAACA,KAAKC,KAAK,EAAE;QACf,OAAO;IACT;IAEA,MAAMC,UAAUC,KAAKC,KAAK,CAAC,AAAEJ,CAAAA,KAAKK,OAAO,IAAI,CAAA,IAAKL,KAAKC,KAAK,GAAI;IAChE,OAAO,CAAC,CAAC,EAAEC,QAAQ,GAAG,CAAC;AACzB;AAEA,OAAO,MAAMI,6BAA6BrC;IACxC,OAAgBsC,OAAO;QACrB7B,QAAQZ,KAAK0C,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;QACAC,eAAe7C,KAAK0C,MAAM,CAAC;YACzBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,uCAAsC;IAEpE,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SACE;YACFJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtB,qCAAqC/C,MAAMgD,OAAO,CAAC;YACjDC,SAAS;YACTP,aAAa;QACf;QACA,wBAAwB1C,MAAMgD,OAAO,CAAC;YACpCC,SAAS;YACTP,aAAa;QACf;QACA,gCAAgC1C,MAAMgD,OAAO,CAAC;YAC5CC,SAAS;YACTP,aAAa;QACf;QACA,0BAA0B1C,MAAMgD,OAAO,CAAC;YACtCC,SAAS;YACTP,aAAa;QACf;QACA,qBAAqB1C,MAAMkD,OAAO,CAAC;YACjCR,aAAa;QACf;QACA,GAAGlC,eAAe;YAChBkC,aAAa;YACbS,WAAW;QACb,EAAE;QACFC,SAASpD,MAAMgD,OAAO,CAAC;YACrBC,SAAS;YACTP,aAAa;YACbW,WAAW;gBAAC;aAAU;QACxB;QACA,GAAG5C,iBAAiB;YAClBiC,aAAa;YACbS,WAAW;QACb,EAAE;QACFG,SAAStD,MAAMyC,MAAM,CAAC;YACpBc,YAAY;gBAACC,IAAI;YAAY;YAC7Bd,aAAa;YACbe,QAAQ;QACV;QACAC,SAAS1D,MAAMgD,OAAO,CAAC;YACrBC,SAAS;YACTP,aAAa;YACbW,WAAW;gBAAC;aAAU;QACxB;QACA,kBAAkBrD,MAAMgD,OAAO,CAAC;YAC9BC,SAAS;YACTP,aAAa;QACf;QACA,iCAAiC1C,MAAMgD,OAAO,CAAC;YAC7CC,SAAS;YACTP,aAAa;QACf;QACAiB,OAAO3D,MAAMyC,MAAM,CAAC;YAClBmB,MAAM;YACNlB,aAAa;YACbmB,KAAK;YACLlB,UAAU;QACZ;IACF,EAAC;IAED,OAAgBmB,gBAA0B;QAAC;KAAiB,CAAA;IAEpDC,gBAA4C;IAC5CC,YAAoB;IACpBC,aAAoC;IACpCC,UAAkB;IAE1B,aAAqBC,UAAUxD,MAAc,EAAkC;QAC7E,IAAI,gBAAgBC,IAAI,CAACD,SAAS;YAChC,OAAOQ,aAAaR;QACtB;QAEA,OAAOA,WAAW,MAAMyD,QAAQC,KAAK,GAAGxE,GAAGyE,gBAAgB,CAAC3D;IAC9D;IAEA,MAAa4D,MAAqB;QAChC,MAAM,EAAC/B,IAAI,EAAEO,KAAK,EAAC,GAAG,MAAM,IAAI,CAACyB,KAAK,CAACjC;QAEvC,MAAM,EACJ,qCAAqCkC,6BAA6B,EAClE,wBAAwBC,kBAAkB,EAC1C,gCAAgCC,0BAA0B,EAC1D,0BAA0BC,oBAAoB,EAC9C,qBAAqBC,gBAAgB,EACrCC,SAASC,WAAW,EACpB3B,OAAO,EACPM,OAAO,EACP,kBAAkBsB,aAAa,EAC/B,iCAAiCC,0BAA0B,EAC3DtB,KAAK,EACN,GAAGZ;QAEJ,MAAMmC,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YACxCC,oBAAoB;YACpBC,UAAU,IAAM9E,iBAAiB,CAAC;QACpC;QAEA,MAAM,EAACI,MAAM,EAAEiC,eAAe0C,gBAAgB,EAAC,GAAG9C;QAElD,IAAI8C,oBAAoB,CAACP,aAAa;YACpC,IAAI,CAACQ,IAAI,CACP;QAEJ;QAEA,MAAMT,UAAUC,eAAeO;QAC/B,IAAI,CAACR,SAAS;YACZ,IAAI,CAACU,KAAK,CAAC,kFAAkF;gBAC3FC,MAAM;YACR;QACF;QAEA,IAAIC,YAAgE;QACpE,IAAIC,oBAAmD;QAEvD,IAAIjC,WAAWN,SAAS;YACtBsC,YAAYhC,UAAU,oBAAoB;YAC1CiC,oBAAoBjC,UAAU,YAAY;QAC5C;QAEA,MAAMkC,SAAS,MAAM3F,oBAAoB;YACvC4F,YAAY;YACZf;YACAI;YACAY,aAAa;YACb,GAAInC,QAAQ;gBAACA;YAAK,IAAI,CAAC,CAAC;QAC1B;QAEA,IAAI;YACF,MAAMjC,SAAS,MAAMa,qBAAqB4B,SAAS,CAACxD;YACpD,MAAMoF,aAAarF,cAAcC;YAEjC,MAAMqF,gBAAgB;gBACpBvB;gBACAC;gBACAC;gBACAC;gBACAgB;gBACAK,YAAY,IAAI,CAACA,UAAU,CAACC,IAAI,CAAC,IAAI;gBACrCR;gBACAC;gBACAX;gBACAC;gBACAkB,KAAK;gBACLvD,eAAekC;gBACfsB,iBAAiBlB;gBACjB,GAAIa,aAAa;oBAACA;gBAAU,IAAI,CAAC,CAAC;gBAClC,GAAIlB,qBAAqBhE,YAAY,CAAC,IAAI;oBAACgE;gBAAgB,CAAC;YAC9D;YAEA,MAAM,EAACwB,OAAO,EAAEC,QAAQ,EAAC,GAAG,MAAMjG,aAAaqB,QAAiCsE;YAEhF,IAAI,IAAI,CAAC9B,SAAS,EAAE;gBAClB,MAAMqC,YAAYjG,SAASkG,KAAKC,GAAG,KAAK,IAAI,CAACvC,SAAS,EAAE;oBAACwC,sBAAsB;gBAAC;gBAChF,IAAI,IAAI,CAAC3C,eAAe,EAAE;oBACxB,IAAI,IAAI,CAACE,YAAY,EAAE;wBACrB0C,cAAc,IAAI,CAAC1C,YAAY;wBAC/B,IAAI,CAACA,YAAY,GAAG;oBACtB;oBACA,IAAI,CAACF,eAAe,CAAC6C,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC5C,WAAW,CAAC,EAAE,EAAEuC,UAAU,CAAC,CAAC;oBACvE,IAAI,CAACxC,eAAe,CAAC8C,OAAO;gBAC9B;YACF;YAEA,IAAI,CAACC,GAAG,CAAC,iDAAiDT,SAASvB;YACnE,IAAI,CAACiC,aAAa,CAACT;QACrB,EAAE,OAAOzE,KAAK;YACZ,IAAI,IAAI,CAACoC,YAAY,EAAE;gBACrB0C,cAAc,IAAI,CAAC1C,YAAY;gBAC/B,IAAI,CAACA,YAAY,GAAG;YACtB;YAEA,IAAI,IAAI,CAACF,eAAe,EAAE;gBACxB,IAAI,CAACA,eAAe,CAACiD,IAAI;YAC3B;YAEA,IAAI,AAACnF,IAAcoF,IAAI,KAAK,wBAAwB;gBAClD,IAAI,CAACzB,KAAK,CACR,CAAC,kEAAkE,EAAE,AAAC3D,IAAcE,OAAO,CAAC,oKAAoK,CAAC,EACjQ;oBAAC0D,MAAM;gBAAC;YAEZ,OAAO;gBACL,IAAI,CAACD,KAAK,CAAC,AAAC3D,IAAcqF,KAAK,IAAI,AAACrF,IAAcE,OAAO,EAAE;oBAAC0D,MAAM;gBAAC;YACrE;QACF;IACF;IAEQQ,WAAWhE,IAAmB,EAAQ;QAC5C,MAAMkF,mBAAmBlF,KAAKC,KAAK;QACnC,MAAMkF,WAAWnF,KAAKoF,IAAI,KAAK,IAAI,CAACrD,WAAW;QAC/C,MAAM7B,UAAUH,cAAcC;QAE9B,IAAIkF,oBAAoBlF,KAAKC,KAAK,KAAKD,KAAKK,OAAO,IAAI,IAAI,CAAC2B,YAAY,EAAE;YACxE0C,cAAc,IAAI,CAAC1C,YAAY;YAC/B,IAAI,CAACA,YAAY,GAAG;QACtB;QAEA,IAAImD,YAAY,CAACD,kBAAkB;YACjC;QACF;QAEA,IAAIC,UAAU;YACZ,IAAI,IAAI,CAAClD,SAAS,EAAE;gBAClB,MAAMqC,YAAYjG,SAASkG,KAAKC,GAAG,KAAK,IAAI,CAACvC,SAAS,EAAE;oBAACwC,sBAAsB;gBAAC;gBAChF,IAAI,IAAI,CAAC3C,eAAe,EAAE;oBACxB,IAAI,CAACA,eAAe,CAAC6C,IAAI,GAAG,GAAGzE,UAAUF,KAAKoF,IAAI,CAAC,EAAE,EAAEd,UAAU,CAAC,CAAC;oBACnE,IAAI,CAACxC,eAAe,CAACuD,MAAM;gBAC7B;YACF;YACA;QACF;QAEA,sBAAsB;QACtB,MAAMC,WAAW,IAAI,CAACvD,WAAW;QACjC,MAAMwD,gBAAgB,IAAI,CAACtD,SAAS;QACpC,IAAI,CAACA,SAAS,GAAGsC,KAAKC,GAAG;QACzB,IAAI,CAACzC,WAAW,GAAG/B,KAAKoF,IAAI;QAE5B,IAAI,IAAI,CAACpD,YAAY,EAAE;YACrB0C,cAAc,IAAI,CAAC1C,YAAY;YAC/B,IAAI,CAACA,YAAY,GAAG;QACtB;QAEA,IAAI,IAAI,CAACF,eAAe,IAAI,IAAI,CAACA,eAAe,CAAC8C,OAAO,IAAIW,eAAe;YACzE,MAAMjB,YAAYjG,SAASkG,KAAKC,GAAG,KAAKe,eAAe;gBACrDd,sBAAsB;YACxB;YACA,IAAI,CAAC3C,eAAe,CAAC6C,IAAI,GAAG,CAAC,OAAO,EAAEW,SAAS,EAAE,EAAEhB,UAAU,CAAC,CAAC;YAC/D,IAAI,CAACxC,eAAe,CAAC8C,OAAO;QAC9B;QAEA,IAAI,CAAC9C,eAAe,GAAG3D,QAAQ,CAAC,KAAK,EAAE6B,KAAKoF,IAAI,CAAC,QAAQ,CAAC,EAAEI,KAAK;QAEjE,IAAI,CAACN,kBAAkB;YACrB,IAAI,CAAClD,YAAY,GAAGyD,YAAY;gBAC9B,IAAI,IAAI,CAACxD,SAAS,IAAI,IAAI,CAACH,eAAe,EAAE;oBAC1C,MAAMwC,YAAYjG,SAASkG,KAAKC,GAAG,KAAK,IAAI,CAACvC,SAAS,EAAE;wBACtDwC,sBAAsB;oBACxB;oBACA,IAAI,CAAC3C,eAAe,CAAC6C,IAAI,GAAG,GAAGzE,UAAUF,KAAKoF,IAAI,CAAC,EAAE,EAAEd,UAAU,CAAC,CAAC;oBACnE,IAAI,CAACxC,eAAe,CAACuD,MAAM;gBAC7B;YACF,GAAG;QACL;IACF;IAEQP,cAAcT,QAA+D,EAAQ;QAC3F,MAAMqB,aAAarB,SAASsB,MAAM,CAAC,CAACrC,OAASA,KAAKsC,IAAI,KAAK;QAE3D,IAAIF,WAAWG,MAAM,KAAK,GAAG;YAC3B;QACF;QAEA,IAAI,CAACvC,IAAI,CAAC,CAAC,+BAA+B,EAAEoC,WAAWG,MAAM,GAAG,IAAI,WAAW,QAAQ,CAAC,CAAC;QAEzF,KAAK,MAAMC,WAAWJ,WAAY;YAChC,IAAII,QAAQpG,GAAG,EAAE;gBACf,IAAI,CAAC4D,IAAI,CAAC,CAAC,EAAE,EAAEwC,QAAQpG,GAAG,EAAE;YAC9B;QACF;IACF;AACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { getCliToken, getGlobalCliClient, getUserConfig } from '@sanity/cli-core';
|
|
2
3
|
import { telemetryDebug } from '../actions/telemetry/telemetryDebug.js';
|
|
3
4
|
import { createExpiringConfig } from '../util/createExpiringConfig.js';
|
|
4
5
|
export const TELEMETRY_API_VERSION = 'v2026-01-22';
|
|
@@ -53,15 +54,35 @@ async function getTelemetryConsent() {
|
|
|
53
54
|
}
|
|
54
55
|
export const TELEMETRY_CONSENT_CONFIG_KEY = 'telemetryConsent';
|
|
55
56
|
const FIVE_MINUTES = 1000 * 60 * 5;
|
|
57
|
+
/**
|
|
58
|
+
* Get a token-scoped cache key for telemetry consent. This ensures that switching
|
|
59
|
+
* users (via login/logout) always results in a cache miss, preventing one user
|
|
60
|
+
* from inheriting another user's cached consent status.
|
|
61
|
+
*
|
|
62
|
+
* @param token - The current auth token, or undefined if not logged in
|
|
63
|
+
* @returns A cache key scoped to the token
|
|
64
|
+
*/ export function getTelemetryConsentCacheKey(token) {
|
|
65
|
+
if (!token) {
|
|
66
|
+
return TELEMETRY_CONSENT_CONFIG_KEY;
|
|
67
|
+
}
|
|
68
|
+
const hash = createHash('sha256').update(token).digest('hex').slice(0, 12);
|
|
69
|
+
return `${TELEMETRY_CONSENT_CONFIG_KEY}:${hash}`;
|
|
70
|
+
}
|
|
56
71
|
/**
|
|
57
72
|
* Fetch the telemetry consent status for the current user
|
|
58
73
|
* @returns The telemetry consent status
|
|
59
74
|
*
|
|
60
75
|
* @internal
|
|
61
76
|
*/ export async function fetchTelemetryConsent() {
|
|
77
|
+
const token = await getCliToken();
|
|
78
|
+
const cacheKey = getTelemetryConsentCacheKey(token);
|
|
79
|
+
// NOTE: createExpiringConfig is instantiated on every call, so in-flight request
|
|
80
|
+
// deduplication (via currentFetch) does not work across concurrent calls to
|
|
81
|
+
// fetchTelemetryConsent(). Two concurrent callers will make two HTTP requests.
|
|
82
|
+
// Consider moving to module-level instance if this becomes a bottleneck.
|
|
62
83
|
const telemetryConsentConfig = createExpiringConfig({
|
|
63
84
|
fetchValue: ()=>getTelemetryConsent(),
|
|
64
|
-
key:
|
|
85
|
+
key: cacheKey,
|
|
65
86
|
onCacheHit () {
|
|
66
87
|
telemetryDebug('Retrieved telemetry consent status from cache');
|
|
67
88
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/services/telemetry.ts"],"sourcesContent":["import {getGlobalCliClient, getUserConfig} from '@sanity/cli-core'\nimport {type TelemetryEvent} from '@sanity/telemetry'\n\nimport {telemetryDebug} from '../actions/telemetry/telemetryDebug.js'\nimport {createExpiringConfig} from '../util/createExpiringConfig.js'\n\nexport const TELEMETRY_API_VERSION = 'v2026-01-22'\n\nexport const VALID_API_STATUSES = ['granted', 'denied', 'unset'] as const\nexport type ValidApiConsentStatus = (typeof VALID_API_STATUSES)[number]\n\nexport async function sendEvents(batch: TelemetryEvent[]) {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: true,\n })\n\n const projectId = process.env.SANITY_TELEMETRY_PROJECT_ID\n\n return client.request({\n body: {batch, projectId},\n json: true,\n method: 'POST',\n uri: '/intake/batch',\n })\n}\n\nasync function getTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: false,\n })\n\n return client.request({tag: 'telemetry-consent', uri: '/intake/telemetry-status'})\n}\n\n/**\n * Check if the given status is a valid consent status\n *\n * @param status - The status to check\n * @returns True if the status is valid, false otherwise\n * @internal\n */\nexport function isValidApiConsentStatus(status: string): status is ValidApiConsentStatus {\n return VALID_API_STATUSES.includes(status as ValidApiConsentStatus)\n}\n\n/**\n * Check if the given response is a valid API consent response\n *\n * @param response - The response to check\n * @returns True if the response is valid, false otherwise\n * @internal\n */\nfunction isValidApiConsentResponse(response: unknown): response is {status: ValidApiConsentStatus} {\n return (\n typeof response === 'object' &&\n response !== null &&\n 'status' in response &&\n typeof response.status === 'string' &&\n isValidApiConsentStatus(response.status)\n )\n}\n\nexport const TELEMETRY_CONSENT_CONFIG_KEY = 'telemetryConsent'\nconst FIVE_MINUTES = 1000 * 60 * 5\n\n/**\n * Fetch the telemetry consent status for the current user\n * @returns The telemetry consent status\n *\n * @internal\n */\nexport async function fetchTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n const telemetryConsentConfig = createExpiringConfig<{\n status: ValidApiConsentStatus\n }>({\n fetchValue: () => getTelemetryConsent(),\n key:
|
|
1
|
+
{"version":3,"sources":["../../src/services/telemetry.ts"],"sourcesContent":["import {createHash} from 'node:crypto'\n\nimport {getCliToken, getGlobalCliClient, getUserConfig} from '@sanity/cli-core'\nimport {type TelemetryEvent} from '@sanity/telemetry'\n\nimport {telemetryDebug} from '../actions/telemetry/telemetryDebug.js'\nimport {createExpiringConfig} from '../util/createExpiringConfig.js'\n\nexport const TELEMETRY_API_VERSION = 'v2026-01-22'\n\nexport const VALID_API_STATUSES = ['granted', 'denied', 'unset'] as const\nexport type ValidApiConsentStatus = (typeof VALID_API_STATUSES)[number]\n\nexport async function sendEvents(batch: TelemetryEvent[]) {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: true,\n })\n\n const projectId = process.env.SANITY_TELEMETRY_PROJECT_ID\n\n return client.request({\n body: {batch, projectId},\n json: true,\n method: 'POST',\n uri: '/intake/batch',\n })\n}\n\nasync function getTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: false,\n })\n\n return client.request({tag: 'telemetry-consent', uri: '/intake/telemetry-status'})\n}\n\n/**\n * Check if the given status is a valid consent status\n *\n * @param status - The status to check\n * @returns True if the status is valid, false otherwise\n * @internal\n */\nexport function isValidApiConsentStatus(status: string): status is ValidApiConsentStatus {\n return VALID_API_STATUSES.includes(status as ValidApiConsentStatus)\n}\n\n/**\n * Check if the given response is a valid API consent response\n *\n * @param response - The response to check\n * @returns True if the response is valid, false otherwise\n * @internal\n */\nfunction isValidApiConsentResponse(response: unknown): response is {status: ValidApiConsentStatus} {\n return (\n typeof response === 'object' &&\n response !== null &&\n 'status' in response &&\n typeof response.status === 'string' &&\n isValidApiConsentStatus(response.status)\n )\n}\n\nexport const TELEMETRY_CONSENT_CONFIG_KEY = 'telemetryConsent'\nconst FIVE_MINUTES = 1000 * 60 * 5\n\n/**\n * Get a token-scoped cache key for telemetry consent. This ensures that switching\n * users (via login/logout) always results in a cache miss, preventing one user\n * from inheriting another user's cached consent status.\n *\n * @param token - The current auth token, or undefined if not logged in\n * @returns A cache key scoped to the token\n */\nexport function getTelemetryConsentCacheKey(token: string | undefined): string {\n if (!token) {\n return TELEMETRY_CONSENT_CONFIG_KEY\n }\n\n const hash = createHash('sha256').update(token).digest('hex').slice(0, 12)\n return `${TELEMETRY_CONSENT_CONFIG_KEY}:${hash}`\n}\n\n/**\n * Fetch the telemetry consent status for the current user\n * @returns The telemetry consent status\n *\n * @internal\n */\nexport async function fetchTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n const token = await getCliToken()\n const cacheKey = getTelemetryConsentCacheKey(token)\n\n // NOTE: createExpiringConfig is instantiated on every call, so in-flight request\n // deduplication (via currentFetch) does not work across concurrent calls to\n // fetchTelemetryConsent(). Two concurrent callers will make two HTTP requests.\n // Consider moving to module-level instance if this becomes a bottleneck.\n const telemetryConsentConfig = createExpiringConfig<{\n status: ValidApiConsentStatus\n }>({\n fetchValue: () => getTelemetryConsent(),\n key: cacheKey,\n onCacheHit() {\n telemetryDebug('Retrieved telemetry consent status from cache')\n },\n onFetch() {\n telemetryDebug('Fetching telemetry consent status...')\n },\n onRevalidate() {\n telemetryDebug('Revalidating cached telemetry consent status...')\n },\n store: getUserConfig(),\n ttl: FIVE_MINUTES,\n validateValue: isValidApiConsentResponse,\n })\n\n return telemetryConsentConfig.get()\n}\n"],"names":["createHash","getCliToken","getGlobalCliClient","getUserConfig","telemetryDebug","createExpiringConfig","TELEMETRY_API_VERSION","VALID_API_STATUSES","sendEvents","batch","client","apiVersion","requireUser","projectId","process","env","SANITY_TELEMETRY_PROJECT_ID","request","body","json","method","uri","getTelemetryConsent","tag","isValidApiConsentStatus","status","includes","isValidApiConsentResponse","response","TELEMETRY_CONSENT_CONFIG_KEY","FIVE_MINUTES","getTelemetryConsentCacheKey","token","hash","update","digest","slice","fetchTelemetryConsent","cacheKey","telemetryConsentConfig","fetchValue","key","onCacheHit","onFetch","onRevalidate","store","ttl","validateValue","get"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAa;AAEtC,SAAQC,WAAW,EAAEC,kBAAkB,EAAEC,aAAa,QAAO,mBAAkB;AAG/E,SAAQC,cAAc,QAAO,yCAAwC;AACrE,SAAQC,oBAAoB,QAAO,kCAAiC;AAEpE,OAAO,MAAMC,wBAAwB,cAAa;AAElD,OAAO,MAAMC,qBAAqB;IAAC;IAAW;IAAU;CAAQ,CAAS;AAGzE,OAAO,eAAeC,WAAWC,KAAuB;IACtD,MAAMC,SAAS,MAAMR,mBAAmB;QACtCS,YAAYL;QACZM,aAAa;IACf;IAEA,MAAMC,YAAYC,QAAQC,GAAG,CAACC,2BAA2B;IAEzD,OAAON,OAAOO,OAAO,CAAC;QACpBC,MAAM;YAACT;YAAOI;QAAS;QACvBM,MAAM;QACNC,QAAQ;QACRC,KAAK;IACP;AACF;AAEA,eAAeC;IAGb,MAAMZ,SAAS,MAAMR,mBAAmB;QACtCS,YAAYL;QACZM,aAAa;IACf;IAEA,OAAOF,OAAOO,OAAO,CAAC;QAACM,KAAK;QAAqBF,KAAK;IAA0B;AAClF;AAEA;;;;;;CAMC,GACD,OAAO,SAASG,wBAAwBC,MAAc;IACpD,OAAOlB,mBAAmBmB,QAAQ,CAACD;AACrC;AAEA;;;;;;CAMC,GACD,SAASE,0BAA0BC,QAAiB;IAClD,OACE,OAAOA,aAAa,YACpBA,aAAa,QACb,YAAYA,YACZ,OAAOA,SAASH,MAAM,KAAK,YAC3BD,wBAAwBI,SAASH,MAAM;AAE3C;AAEA,OAAO,MAAMI,+BAA+B,mBAAkB;AAC9D,MAAMC,eAAe,OAAO,KAAK;AAEjC;;;;;;;CAOC,GACD,OAAO,SAASC,4BAA4BC,KAAyB;IACnE,IAAI,CAACA,OAAO;QACV,OAAOH;IACT;IAEA,MAAMI,OAAOjC,WAAW,UAAUkC,MAAM,CAACF,OAAOG,MAAM,CAAC,OAAOC,KAAK,CAAC,GAAG;IACvE,OAAO,GAAGP,6BAA6B,CAAC,EAAEI,MAAM;AAClD;AAEA;;;;;CAKC,GACD,OAAO,eAAeI;IAGpB,MAAML,QAAQ,MAAM/B;IACpB,MAAMqC,WAAWP,4BAA4BC;IAE7C,iFAAiF;IACjF,4EAA4E;IAC5E,+EAA+E;IAC/E,yEAAyE;IACzE,MAAMO,yBAAyBlC,qBAE5B;QACDmC,YAAY,IAAMlB;QAClBmB,KAAKH;QACLI;YACEtC,eAAe;QACjB;QACAuC;YACEvC,eAAe;QACjB;QACAwC;YACExC,eAAe;QACjB;QACAyC,OAAO1C;QACP2C,KAAKhB;QACLiB,eAAepB;IACjB;IAEA,OAAOY,uBAAuBS,GAAG;AACnC"}
|
|
@@ -2,8 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import { isInteractive } from '@sanity/cli-core';
|
|
3
3
|
import { getRunningPackageManager } from '@sanity/cli-core/package-manager';
|
|
4
4
|
import { select } from '@sanity/cli-core/ux';
|
|
5
|
-
|
|
6
|
-
import { default as preferredPM } from 'preferred-pm';
|
|
5
|
+
import { preferredPM } from 'preferred-pm';
|
|
7
6
|
import which from 'which';
|
|
8
7
|
const EXPERIMENTAL = new Set([
|
|
9
8
|
'bun'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/util/packageManager/packageManagerChoice.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {isInteractive} from '@sanity/cli-core'\nimport {getRunningPackageManager} from '@sanity/cli-core/package-manager'\nimport {select} from '@sanity/cli-core/ux'\n// eslint-disable-next-line unicorn/no-named-default\nimport {default as preferredPM} from 'preferred-pm'\nimport which from 'which'\n\nexport type PackageManager = 'bun' | 'manual' | 'npm' | 'pnpm' | 'yarn'\n\nconst EXPERIMENTAL = new Set(['bun'])\n\nexport const ALLOWED_PACKAGE_MANAGERS: readonly PackageManager[] = [\n 'npm',\n 'yarn',\n 'pnpm',\n 'bun',\n 'manual',\n] as const\n\nexport const allowedPackageManagersString = ALLOWED_PACKAGE_MANAGERS.join(' | ')\n\n/**\n * Attempts to resolve the most optimal package manager to use to install/upgrade\n * packages/dependencies at a given path. It does so by looking for package manager\n * specific lockfiles. If it finds a lockfile belonging to a certain package manager,\n * it prioritizes this one. However, if that package manager is not installed, it will\n * prompt the user for which one they want to use and hint at the most optimal one\n * not being installed.\n *\n * Note that this function also takes local npm binary paths into account - for instance,\n * `yarn` can be installed as a dependency of the project instead of globally, and it\n * will use that is available.\n *\n * The user can also select 'manual' to skip the process and run their preferred package\n * manager manually. Commands using this function must take this `manual` choice into\n * account and act accordingly if chosen.\n *\n * @param workDir - The working directory where a lockfile is most likely to be present\n * @param options - Pass `interactive: false` to fall back to npm if most optimal is\n * not available, instead of prompting\n * @returns Object of `chosen` and, if a lockfile is found, the `mostOptimal` choice\n */\nexport async function getPackageManagerChoice(\n workDir: string,\n options: {interactive: boolean},\n): Promise<{chosen: PackageManager; mostOptimal?: PackageManager}> {\n const rootDir = workDir || process.cwd()\n const preferred = (await preferredPM(rootDir))?.name\n\n if (preferred && (await hasCommand(preferred, rootDir))) {\n // There is an optimal/preferred package manager, and the user has it installed!\n return {chosen: preferred, mostOptimal: preferred}\n }\n\n const mostLikelyPM = await getMostLikelyInstalledPackageManager(rootDir)\n const interactive =\n typeof options.interactive === 'boolean' ? options.interactive : isInteractive()\n if (!interactive) {\n // We can't ask the user for their preference, so fall back to either the one that is being run\n // or whatever is installed on the system (npm being the preferred choice).\n // Note that the most optimal choice is already picked above if available.\n return {chosen: mostLikelyPM || (await getFallback(rootDir)), mostOptimal: preferred}\n }\n\n // We can ask the user for their preference, hurray!\n const messageSuffix = preferred ? ` (preferred is ${preferred}, but is not installed)` : ''\n const installed = await getAvailablePackageManagers(rootDir)\n const chosen = await select<PackageManager>({\n choices: installed.map((pm) => ({\n name: EXPERIMENTAL.has(pm) ? `${pm} (experimental)` : pm,\n value: pm,\n })),\n default: preferred || mostLikelyPM,\n message: `Package manager to use for installing dependencies?${messageSuffix}`,\n })\n\n return {chosen, mostOptimal: preferred}\n}\n\nasync function getFallback(cwd: string): Promise<PackageManager> {\n if (await hasNpmInstalled(cwd)) {\n return 'npm'\n }\n\n if (await hasYarnInstalled(cwd)) {\n return 'yarn'\n }\n\n if (await hasPnpmInstalled(cwd)) {\n return 'pnpm'\n }\n\n if (await hasBunInstalled(cwd)) {\n return 'bun'\n }\n\n return 'manual'\n}\n\nasync function getAvailablePackageManagers(cwd: string): Promise<PackageManager[]> {\n const [npm, yarn, pnpm, bun] = await Promise.all([\n hasNpmInstalled(cwd),\n hasYarnInstalled(cwd),\n hasPnpmInstalled(cwd),\n hasBunInstalled(cwd),\n ])\n\n const choices = [npm && 'npm', yarn && 'yarn', pnpm && 'pnpm', bun && 'bun', 'manual']\n return choices.filter((pm): pm is PackageManager => pm !== false)\n}\n\nfunction hasNpmInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('npm', cwd)\n}\n\nfunction hasYarnInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('yarn', cwd)\n}\n\nfunction hasPnpmInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('pnpm', cwd)\n}\n\nfunction hasBunInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('bun', cwd)\n}\n\nfunction getNpmRunPath(cwd: string): string {\n let previous\n let cwdPath = path.resolve(cwd)\n const result: string[] = []\n\n while (previous !== cwdPath) {\n result.push(path.join(cwdPath, 'node_modules', '.bin'))\n previous = cwdPath\n cwdPath = path.resolve(cwdPath, '..')\n }\n\n result.push(path.resolve(cwd, process.execPath, '..'))\n\n const pathEnv = process.env[getPathEnvVarKey()]\n return [...result, pathEnv].join(path.delimiter)\n}\n\nexport function getPartialEnvWithNpmPath(cwd: string): NodeJS.ProcessEnv {\n const key = getPathEnvVarKey()\n return {[key]: getNpmRunPath(cwd)}\n}\n\nfunction getPathEnvVarKey(): string {\n if (process.platform !== 'win32') {\n return 'PATH'\n }\n\n return (\n Object.keys(process.env)\n .toReversed()\n .find((key) => key.toUpperCase() === 'PATH') || 'Path'\n )\n}\n\nfunction getCommandPath(cmd: string, cwd?: string): Promise<string | null> {\n const options = cwd ? {path: getNpmRunPath(cwd)} : undefined\n return which(cmd, options).catch(() => null)\n}\n\nfunction hasCommand(cmd: string, cwd?: string): Promise<boolean> {\n return getCommandPath(cmd, cwd).then((cmdPath) => cmdPath !== null)\n}\n\nasync function getMostLikelyInstalledPackageManager(\n rootDir: string,\n): Promise<PackageManager | undefined> {\n const installed = await getAvailablePackageManagers(rootDir)\n const running = getRunningPackageManager()\n return running && installed.includes(running) ? running : undefined\n}\n"],"names":["path","isInteractive","getRunningPackageManager","select","default","preferredPM","which","EXPERIMENTAL","Set","ALLOWED_PACKAGE_MANAGERS","allowedPackageManagersString","join","getPackageManagerChoice","workDir","options","rootDir","process","cwd","preferred","name","hasCommand","chosen","mostOptimal","mostLikelyPM","getMostLikelyInstalledPackageManager","interactive","getFallback","messageSuffix","installed","getAvailablePackageManagers","choices","map","pm","has","value","message","hasNpmInstalled","hasYarnInstalled","hasPnpmInstalled","hasBunInstalled","npm","yarn","pnpm","bun","Promise","all","filter","getNpmRunPath","previous","cwdPath","resolve","result","push","execPath","pathEnv","env","getPathEnvVarKey","delimiter","getPartialEnvWithNpmPath","key","platform","Object","keys","toReversed","find","toUpperCase","getCommandPath","cmd","undefined","catch","then","cmdPath","running","includes"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAE5B,SAAQC,aAAa,QAAO,mBAAkB;AAC9C,SAAQC,wBAAwB,QAAO,mCAAkC;AACzE,SAAQC,MAAM,QAAO,sBAAqB;AAC1C,oDAAoD;AACpD,SAAQC,WAAWC,WAAW,QAAO,eAAc;AACnD,OAAOC,WAAW,QAAO;AAIzB,MAAMC,eAAe,IAAIC,IAAI;IAAC;CAAM;AAEpC,OAAO,MAAMC,2BAAsD;IACjE;IACA;IACA;IACA;IACA;CACD,CAAS;AAEV,OAAO,MAAMC,+BAA+BD,yBAAyBE,IAAI,CAAC,OAAM;AAEhF;;;;;;;;;;;;;;;;;;;;CAoBC,GACD,OAAO,eAAeC,wBACpBC,OAAe,EACfC,OAA+B;IAE/B,MAAMC,UAAUF,WAAWG,QAAQC,GAAG;IACtC,MAAMC,YAAa,CAAA,MAAMb,YAAYU,QAAO,GAAII;IAEhD,IAAID,aAAc,MAAME,WAAWF,WAAWH,UAAW;QACvD,gFAAgF;QAChF,OAAO;YAACM,QAAQH;YAAWI,aAAaJ;QAAS;IACnD;IAEA,MAAMK,eAAe,MAAMC,qCAAqCT;IAChE,MAAMU,cACJ,OAAOX,QAAQW,WAAW,KAAK,YAAYX,QAAQW,WAAW,GAAGxB;IACnE,IAAI,CAACwB,aAAa;QAChB,+FAA+F;QAC/F,2EAA2E;QAC3E,0EAA0E;QAC1E,OAAO;YAACJ,QAAQE,gBAAiB,MAAMG,YAAYX;YAAWO,aAAaJ;QAAS;IACtF;IAEA,oDAAoD;IACpD,MAAMS,gBAAgBT,YAAY,CAAC,eAAe,EAAEA,UAAU,uBAAuB,CAAC,GAAG;IACzF,MAAMU,YAAY,MAAMC,4BAA4Bd;IACpD,MAAMM,SAAS,MAAMlB,OAAuB;QAC1C2B,SAASF,UAAUG,GAAG,CAAC,CAACC,KAAQ,CAAA;gBAC9Bb,MAAMZ,aAAa0B,GAAG,CAACD,MAAM,GAAGA,GAAG,eAAe,CAAC,GAAGA;gBACtDE,OAAOF;YACT,CAAA;QACA5B,SAASc,aAAaK;QACtBY,SAAS,CAAC,mDAAmD,EAAER,eAAe;IAChF;IAEA,OAAO;QAACN;QAAQC,aAAaJ;IAAS;AACxC;AAEA,eAAeQ,YAAYT,GAAW;IACpC,IAAI,MAAMmB,gBAAgBnB,MAAM;QAC9B,OAAO;IACT;IAEA,IAAI,MAAMoB,iBAAiBpB,MAAM;QAC/B,OAAO;IACT;IAEA,IAAI,MAAMqB,iBAAiBrB,MAAM;QAC/B,OAAO;IACT;IAEA,IAAI,MAAMsB,gBAAgBtB,MAAM;QAC9B,OAAO;IACT;IAEA,OAAO;AACT;AAEA,eAAeY,4BAA4BZ,GAAW;IACpD,MAAM,CAACuB,KAAKC,MAAMC,MAAMC,IAAI,GAAG,MAAMC,QAAQC,GAAG,CAAC;QAC/CT,gBAAgBnB;QAChBoB,iBAAiBpB;QACjBqB,iBAAiBrB;QACjBsB,gBAAgBtB;KACjB;IAED,MAAMa,UAAU;QAACU,OAAO;QAAOC,QAAQ;QAAQC,QAAQ;QAAQC,OAAO;QAAO;KAAS;IACtF,OAAOb,QAAQgB,MAAM,CAAC,CAACd,KAA6BA,OAAO;AAC7D;AAEA,SAASI,gBAAgBnB,GAAY;IACnC,OAAOG,WAAW,OAAOH;AAC3B;AAEA,SAASoB,iBAAiBpB,GAAY;IACpC,OAAOG,WAAW,QAAQH;AAC5B;AAEA,SAASqB,iBAAiBrB,GAAY;IACpC,OAAOG,WAAW,QAAQH;AAC5B;AAEA,SAASsB,gBAAgBtB,GAAY;IACnC,OAAOG,WAAW,OAAOH;AAC3B;AAEA,SAAS8B,cAAc9B,GAAW;IAChC,IAAI+B;IACJ,IAAIC,UAAUjD,KAAKkD,OAAO,CAACjC;IAC3B,MAAMkC,SAAmB,EAAE;IAE3B,MAAOH,aAAaC,QAAS;QAC3BE,OAAOC,IAAI,CAACpD,KAAKW,IAAI,CAACsC,SAAS,gBAAgB;QAC/CD,WAAWC;QACXA,UAAUjD,KAAKkD,OAAO,CAACD,SAAS;IAClC;IAEAE,OAAOC,IAAI,CAACpD,KAAKkD,OAAO,CAACjC,KAAKD,QAAQqC,QAAQ,EAAE;IAEhD,MAAMC,UAAUtC,QAAQuC,GAAG,CAACC,mBAAmB;IAC/C,OAAO;WAAIL;QAAQG;KAAQ,CAAC3C,IAAI,CAACX,KAAKyD,SAAS;AACjD;AAEA,OAAO,SAASC,yBAAyBzC,GAAW;IAClD,MAAM0C,MAAMH;IACZ,OAAO;QAAC,CAACG,IAAI,EAAEZ,cAAc9B;IAAI;AACnC;AAEA,SAASuC;IACP,IAAIxC,QAAQ4C,QAAQ,KAAK,SAAS;QAChC,OAAO;IACT;IAEA,OACEC,OAAOC,IAAI,CAAC9C,QAAQuC,GAAG,EACpBQ,UAAU,GACVC,IAAI,CAAC,CAACL,MAAQA,IAAIM,WAAW,OAAO,WAAW;AAEtD;AAEA,SAASC,eAAeC,GAAW,EAAElD,GAAY;IAC/C,MAAMH,UAAUG,MAAM;QAACjB,MAAM+C,cAAc9B;IAAI,IAAImD;IACnD,OAAO9D,MAAM6D,KAAKrD,SAASuD,KAAK,CAAC,IAAM;AACzC;AAEA,SAASjD,WAAW+C,GAAW,EAAElD,GAAY;IAC3C,OAAOiD,eAAeC,KAAKlD,KAAKqD,IAAI,CAAC,CAACC,UAAYA,YAAY;AAChE;AAEA,eAAe/C,qCACbT,OAAe;IAEf,MAAMa,YAAY,MAAMC,4BAA4Bd;IACpD,MAAMyD,UAAUtE;IAChB,OAAOsE,WAAW5C,UAAU6C,QAAQ,CAACD,WAAWA,UAAUJ;AAC5D"}
|
|
1
|
+
{"version":3,"sources":["../../../src/util/packageManager/packageManagerChoice.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {isInteractive} from '@sanity/cli-core'\nimport {getRunningPackageManager} from '@sanity/cli-core/package-manager'\nimport {select} from '@sanity/cli-core/ux'\nimport {preferredPM} from 'preferred-pm'\nimport which from 'which'\n\nexport type PackageManager = 'bun' | 'manual' | 'npm' | 'pnpm' | 'yarn'\n\nconst EXPERIMENTAL = new Set(['bun'])\n\nexport const ALLOWED_PACKAGE_MANAGERS: readonly PackageManager[] = [\n 'npm',\n 'yarn',\n 'pnpm',\n 'bun',\n 'manual',\n] as const\n\nexport const allowedPackageManagersString = ALLOWED_PACKAGE_MANAGERS.join(' | ')\n\n/**\n * Attempts to resolve the most optimal package manager to use to install/upgrade\n * packages/dependencies at a given path. It does so by looking for package manager\n * specific lockfiles. If it finds a lockfile belonging to a certain package manager,\n * it prioritizes this one. However, if that package manager is not installed, it will\n * prompt the user for which one they want to use and hint at the most optimal one\n * not being installed.\n *\n * Note that this function also takes local npm binary paths into account - for instance,\n * `yarn` can be installed as a dependency of the project instead of globally, and it\n * will use that is available.\n *\n * The user can also select 'manual' to skip the process and run their preferred package\n * manager manually. Commands using this function must take this `manual` choice into\n * account and act accordingly if chosen.\n *\n * @param workDir - The working directory where a lockfile is most likely to be present\n * @param options - Pass `interactive: false` to fall back to npm if most optimal is\n * not available, instead of prompting\n * @returns Object of `chosen` and, if a lockfile is found, the `mostOptimal` choice\n */\nexport async function getPackageManagerChoice(\n workDir: string,\n options: {interactive: boolean},\n): Promise<{chosen: PackageManager; mostOptimal?: PackageManager}> {\n const rootDir = workDir || process.cwd()\n const preferred = (await preferredPM(rootDir))?.name\n\n if (preferred && (await hasCommand(preferred, rootDir))) {\n // There is an optimal/preferred package manager, and the user has it installed!\n return {chosen: preferred, mostOptimal: preferred}\n }\n\n const mostLikelyPM = await getMostLikelyInstalledPackageManager(rootDir)\n const interactive =\n typeof options.interactive === 'boolean' ? options.interactive : isInteractive()\n if (!interactive) {\n // We can't ask the user for their preference, so fall back to either the one that is being run\n // or whatever is installed on the system (npm being the preferred choice).\n // Note that the most optimal choice is already picked above if available.\n return {chosen: mostLikelyPM || (await getFallback(rootDir)), mostOptimal: preferred}\n }\n\n // We can ask the user for their preference, hurray!\n const messageSuffix = preferred ? ` (preferred is ${preferred}, but is not installed)` : ''\n const installed = await getAvailablePackageManagers(rootDir)\n const chosen = await select<PackageManager>({\n choices: installed.map((pm) => ({\n name: EXPERIMENTAL.has(pm) ? `${pm} (experimental)` : pm,\n value: pm,\n })),\n default: preferred || mostLikelyPM,\n message: `Package manager to use for installing dependencies?${messageSuffix}`,\n })\n\n return {chosen, mostOptimal: preferred}\n}\n\nasync function getFallback(cwd: string): Promise<PackageManager> {\n if (await hasNpmInstalled(cwd)) {\n return 'npm'\n }\n\n if (await hasYarnInstalled(cwd)) {\n return 'yarn'\n }\n\n if (await hasPnpmInstalled(cwd)) {\n return 'pnpm'\n }\n\n if (await hasBunInstalled(cwd)) {\n return 'bun'\n }\n\n return 'manual'\n}\n\nasync function getAvailablePackageManagers(cwd: string): Promise<PackageManager[]> {\n const [npm, yarn, pnpm, bun] = await Promise.all([\n hasNpmInstalled(cwd),\n hasYarnInstalled(cwd),\n hasPnpmInstalled(cwd),\n hasBunInstalled(cwd),\n ])\n\n const choices = [npm && 'npm', yarn && 'yarn', pnpm && 'pnpm', bun && 'bun', 'manual']\n return choices.filter((pm): pm is PackageManager => pm !== false)\n}\n\nfunction hasNpmInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('npm', cwd)\n}\n\nfunction hasYarnInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('yarn', cwd)\n}\n\nfunction hasPnpmInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('pnpm', cwd)\n}\n\nfunction hasBunInstalled(cwd?: string): Promise<boolean> {\n return hasCommand('bun', cwd)\n}\n\nfunction getNpmRunPath(cwd: string): string {\n let previous\n let cwdPath = path.resolve(cwd)\n const result: string[] = []\n\n while (previous !== cwdPath) {\n result.push(path.join(cwdPath, 'node_modules', '.bin'))\n previous = cwdPath\n cwdPath = path.resolve(cwdPath, '..')\n }\n\n result.push(path.resolve(cwd, process.execPath, '..'))\n\n const pathEnv = process.env[getPathEnvVarKey()]\n return [...result, pathEnv].join(path.delimiter)\n}\n\nexport function getPartialEnvWithNpmPath(cwd: string): NodeJS.ProcessEnv {\n const key = getPathEnvVarKey()\n return {[key]: getNpmRunPath(cwd)}\n}\n\nfunction getPathEnvVarKey(): string {\n if (process.platform !== 'win32') {\n return 'PATH'\n }\n\n return (\n Object.keys(process.env)\n .toReversed()\n .find((key) => key.toUpperCase() === 'PATH') || 'Path'\n )\n}\n\nfunction getCommandPath(cmd: string, cwd?: string): Promise<string | null> {\n const options = cwd ? {path: getNpmRunPath(cwd)} : undefined\n return which(cmd, options).catch(() => null)\n}\n\nfunction hasCommand(cmd: string, cwd?: string): Promise<boolean> {\n return getCommandPath(cmd, cwd).then((cmdPath) => cmdPath !== null)\n}\n\nasync function getMostLikelyInstalledPackageManager(\n rootDir: string,\n): Promise<PackageManager | undefined> {\n const installed = await getAvailablePackageManagers(rootDir)\n const running = getRunningPackageManager()\n return running && installed.includes(running) ? running : undefined\n}\n"],"names":["path","isInteractive","getRunningPackageManager","select","preferredPM","which","EXPERIMENTAL","Set","ALLOWED_PACKAGE_MANAGERS","allowedPackageManagersString","join","getPackageManagerChoice","workDir","options","rootDir","process","cwd","preferred","name","hasCommand","chosen","mostOptimal","mostLikelyPM","getMostLikelyInstalledPackageManager","interactive","getFallback","messageSuffix","installed","getAvailablePackageManagers","choices","map","pm","has","value","default","message","hasNpmInstalled","hasYarnInstalled","hasPnpmInstalled","hasBunInstalled","npm","yarn","pnpm","bun","Promise","all","filter","getNpmRunPath","previous","cwdPath","resolve","result","push","execPath","pathEnv","env","getPathEnvVarKey","delimiter","getPartialEnvWithNpmPath","key","platform","Object","keys","toReversed","find","toUpperCase","getCommandPath","cmd","undefined","catch","then","cmdPath","running","includes"],"mappings":"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"}
|
package/oclif.manifest.json
CHANGED
|
@@ -1819,16 +1819,20 @@
|
|
|
1819
1819
|
"description": "Import documents to a Sanity dataset",
|
|
1820
1820
|
"examples": [
|
|
1821
1821
|
{
|
|
1822
|
-
"command": "<%= config.bin %> <%= command.id %> -d staging
|
|
1822
|
+
"command": "<%= config.bin %> <%= command.id %> -d staging my-dataset.ndjson",
|
|
1823
1823
|
"description": "Import \"./my-dataset.ndjson\" into dataset \"staging\""
|
|
1824
1824
|
},
|
|
1825
1825
|
{
|
|
1826
|
-
"command": "cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -
|
|
1826
|
+
"command": "cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -",
|
|
1827
1827
|
"description": "Import into dataset \"test\" from stdin"
|
|
1828
1828
|
},
|
|
1829
1829
|
{
|
|
1830
|
-
"command": "<%= config.bin %> <%= command.id %> -p projectId -d staging
|
|
1830
|
+
"command": "<%= config.bin %> <%= command.id %> -p projectId -d staging my-dataset.ndjson",
|
|
1831
1831
|
"description": "Import with explicit project ID (overrides CLI configuration)"
|
|
1832
|
+
},
|
|
1833
|
+
{
|
|
1834
|
+
"command": "<%= config.bin %> <%= command.id %> -d staging -t someSecretToken my-dataset.ndjson",
|
|
1835
|
+
"description": "Import with an explicit token (e.g. for CI/CD)"
|
|
1832
1836
|
}
|
|
1833
1837
|
],
|
|
1834
1838
|
"flags": {
|
|
@@ -5055,5 +5059,5 @@
|
|
|
5055
5059
|
]
|
|
5056
5060
|
}
|
|
5057
5061
|
},
|
|
5058
|
-
"version": "6.2.
|
|
5062
|
+
"version": "6.2.1"
|
|
5059
5063
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli",
|
|
3
|
-
"version": "6.2.
|
|
3
|
+
"version": "6.2.1",
|
|
4
4
|
"description": "Sanity CLI tool for managing Sanity projects and organizations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -51,21 +51,21 @@
|
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@oclif/core": "^4.
|
|
55
|
-
"@oclif/plugin-help": "^6.2.
|
|
56
|
-
"@oclif/plugin-not-found": "^3.2.
|
|
57
|
-
"@sanity/client": "^7.
|
|
54
|
+
"@oclif/core": "^4.10.2",
|
|
55
|
+
"@oclif/plugin-help": "^6.2.39",
|
|
56
|
+
"@oclif/plugin-not-found": "^3.2.76",
|
|
57
|
+
"@sanity/client": "^7.20.0",
|
|
58
58
|
"@sanity/codegen": "^6.0.1",
|
|
59
59
|
"@sanity/descriptors": "^1.3.0",
|
|
60
60
|
"@sanity/export": "^6.1.0",
|
|
61
61
|
"@sanity/generate-help-url": "^4.0.0",
|
|
62
62
|
"@sanity/id-utils": "^1.0.0",
|
|
63
|
-
"@sanity/import": "^
|
|
64
|
-
"@sanity/migrate": "^6.
|
|
65
|
-
"@sanity/runtime-cli": "^14.
|
|
63
|
+
"@sanity/import": "^6.0.0",
|
|
64
|
+
"@sanity/migrate": "^6.1.0",
|
|
65
|
+
"@sanity/runtime-cli": "^14.6.1",
|
|
66
66
|
"@sanity/schema": "^5.17.1",
|
|
67
67
|
"@sanity/telemetry": "^0.8.1",
|
|
68
|
-
"@sanity/template-validator": "^3.0
|
|
68
|
+
"@sanity/template-validator": "^3.1.0",
|
|
69
69
|
"@sanity/types": "^5.17.1",
|
|
70
70
|
"@sanity/ui": "^3.1.14",
|
|
71
71
|
"@sanity/worker-channels": "^2.0.0",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
"peek-stream": "^1.1.3",
|
|
98
98
|
"picomatch": "^4.0.3",
|
|
99
99
|
"pluralize-esm": "^9.0.5",
|
|
100
|
-
"preferred-pm": "^
|
|
100
|
+
"preferred-pm": "^5.0.0",
|
|
101
101
|
"pretty-ms": "^9.3.0",
|
|
102
102
|
"promise-props-recursive": "^2.0.2",
|
|
103
103
|
"react": "^19.2.4",
|
|
@@ -118,14 +118,14 @@
|
|
|
118
118
|
"which": "^6.0.1",
|
|
119
119
|
"yaml": "^2.8.2",
|
|
120
120
|
"zod": "^4.3.6",
|
|
121
|
-
"@sanity/cli-core": "1.2.
|
|
121
|
+
"@sanity/cli-core": "1.2.1"
|
|
122
122
|
},
|
|
123
123
|
"devDependencies": {
|
|
124
124
|
"@eslint/compat": "^2.0.3",
|
|
125
125
|
"@sanity/pkg-utils": "^10.4.11",
|
|
126
126
|
"@swc/cli": "^0.8.0",
|
|
127
127
|
"@swc/core": "^1.15.18",
|
|
128
|
-
"@types/debug": "^4.1.
|
|
128
|
+
"@types/debug": "^4.1.13",
|
|
129
129
|
"@types/gunzip-maybe": "^1.4.3",
|
|
130
130
|
"@types/lodash-es": "^4.17.12",
|
|
131
131
|
"@types/minimist": "^1.2.5",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
143
143
|
"eslint": "^9.39.4",
|
|
144
144
|
"nock": "^14.0.11",
|
|
145
|
-
"oclif": "^4.22.
|
|
145
|
+
"oclif": "^4.22.93",
|
|
146
146
|
"publint": "^0.3.18",
|
|
147
147
|
"rimraf": "^6.0.1",
|
|
148
148
|
"sanity": "^5.17.1",
|
|
@@ -151,8 +151,8 @@
|
|
|
151
151
|
"vitest": "^4.1.0",
|
|
152
152
|
"@repo/package.config": "0.0.1",
|
|
153
153
|
"@repo/tsconfig": "3.70.0",
|
|
154
|
-
"@sanity/cli
|
|
155
|
-
"@sanity/
|
|
154
|
+
"@sanity/eslint-config-cli": "1.0.1",
|
|
155
|
+
"@sanity/cli-test": "0.2.7"
|
|
156
156
|
},
|
|
157
157
|
"engines": {
|
|
158
158
|
"node": ">=20.19.1 <22 || >=22.12"
|