sanity 5.3.0-next.14 → 5.3.0-next.16

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.
@@ -14,18 +14,19 @@ import { glob } from "tinyglobby";
14
14
  import { debug as debug$1 } from "./_internal.js";
15
15
  import { determineTargetMediaLibrary, MINIMUM_API_VERSION } from "./determineTargetMediaLibrary.js";
16
16
  import readline from "node:readline";
17
- async function* findNdjsonEntry(ndjson, matcher) {
17
+ async function readNdjsonFile(ndjson) {
18
18
  const lines = readline.createInterface({
19
19
  input: ndjson
20
- });
21
- for await (const line of lines) {
22
- const parsed = JSON.parse(line.trim());
23
- if (matcher(parsed)) {
24
- yield parsed, lines.close();
25
- return;
20
+ }), entries = [];
21
+ try {
22
+ for await (const line of lines) {
23
+ const trimmed = line.trim();
24
+ trimmed && entries.push(JSON.parse(trimmed));
26
25
  }
26
+ } finally {
27
+ lines.close(), ndjson.destroy();
27
28
  }
28
- yield void 0;
29
+ return entries;
29
30
  }
30
31
  const debug = debug$1.extend("importMedia"), DEFAULT_CONCURRENCY = 6, importAssetsAction = async (args, context) => {
31
32
  const {
@@ -69,15 +70,18 @@ function importer(options) {
69
70
  const fileCount = files.length + images.length;
70
71
  if (fileCount === 0)
71
72
  throw new Error("No assets to import");
72
- const context = {
73
- ...options,
74
- workingPath,
75
- ndjson: () => aspectsNdjsonPath ? createReadStream(aspectsNdjsonPath) : null
76
- };
77
- return from(files).pipe(switchMap((file) => zip(of("file"), of(file))), mergeWith(from(images).pipe(switchMap((file) => zip(of("image"), of(file))))), fetchExistingAssets(context), uploadAsset(context), resolveAspectData(context), setAspects(context), map((asset) => ({
78
- asset,
79
- fileCount
80
- })));
73
+ const aspectsDataPromise = aspectsNdjsonPath ? readNdjsonFile(createReadStream(aspectsNdjsonPath)) : Promise.resolve([]);
74
+ return from(aspectsDataPromise).pipe(mergeMap((aspectsData) => {
75
+ const context = {
76
+ ...options,
77
+ workingPath,
78
+ aspectsData
79
+ };
80
+ return from(files).pipe(switchMap((file) => zip(of("file"), of(file))), mergeWith(from(images).pipe(switchMap((file) => zip(of("image"), of(file))))), fetchExistingAssets(context), uploadAsset(context), resolveAspectData(context), setAspects(context), map((asset) => ({
81
+ asset,
82
+ fileCount
83
+ })));
84
+ }));
81
85
  }));
82
86
  }
83
87
  function resolveSource({
@@ -152,17 +156,19 @@ function fetchExistingAssets({
152
156
  });
153
157
  }
154
158
  function resolveAspectData({
155
- ndjson
159
+ aspectsData
156
160
  }) {
157
- return mergeMap((resolvedAsset) => {
158
- const ndjsonStream = ndjson();
159
- return ndjsonStream ? from(findNdjsonEntry(ndjsonStream, (line) => typeof line == "object" && line !== null && "filename" in line && line.filename === resolvedAsset.originalFilename)).pipe(map((aspectsFromImport) => ({
161
+ return map((resolvedAsset) => {
162
+ if (!aspectsData || aspectsData.length === 0)
163
+ return {
164
+ ...resolvedAsset,
165
+ aspects: void 0
166
+ };
167
+ const aspectsFromImport = aspectsData.find((entry) => entry.filename === resolvedAsset.originalFilename);
168
+ return {
160
169
  ...resolvedAsset,
161
170
  aspects: aspectsFromImport?.aspects
162
- }))) : of({
163
- ...resolvedAsset,
164
- aspects: void 0
165
- });
171
+ };
166
172
  });
167
173
  }
168
174
  function setAspects({
@@ -1 +1 @@
1
- {"version":3,"file":"importAssetsAction.js","sources":["../../src/_internal/cli/actions/media/lib/findNdjsonEntry.ts","../../src/_internal/cli/actions/media/importAssetsAction.ts"],"sourcesContent":["import readline from 'node:readline'\nimport {Readable} from 'node:stream'\n\n/**\n * Find the first matching entry in the provided NDJSON stream.\n *\n * @internal\n */\nexport async function* findNdjsonEntry<Type>(\n ndjson: Readable,\n matcher: (line: Type) => boolean,\n): AsyncGenerator<Type | undefined> {\n const lines = readline.createInterface({\n input: ndjson,\n })\n\n for await (const line of lines) {\n const parsed = JSON.parse(line.trim())\n if (matcher(parsed)) {\n yield parsed\n lines.close()\n return\n }\n }\n\n yield undefined\n}\n","import {createHash} from 'node:crypto'\nimport {createReadStream, type ReadStream} from 'node:fs'\nimport fs, {mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {text} from 'node:stream/consumers'\nimport {pipeline} from 'node:stream/promises'\n\nimport {\n type CliCommandAction,\n type CliCommandContext,\n type CliOutputter,\n type SanityClient,\n} from '@sanity/cli'\nimport {type FileAsset, type ImageAsset, type SanityDocument} from '@sanity/types'\nimport {type Chalk} from 'chalk'\nimport gunzipMaybe from 'gunzip-maybe'\nimport isTar from 'is-tar'\n// @ts-expect-error `peek-stream` module currently untyped\nimport peek from 'peek-stream'\nimport {\n catchError,\n EMPTY,\n filter,\n from,\n map,\n mergeMap,\n mergeWith,\n type Observable,\n of,\n type OperatorFunction,\n pipe,\n scan,\n switchMap,\n tap,\n zip,\n} from 'rxjs'\nimport tar from 'tar-fs'\nimport {glob} from 'tinyglobby'\n\nimport {debug as baseDebug} from '../../debug'\nimport {MINIMUM_API_VERSION} from './constants'\nimport {determineTargetMediaLibrary} from './lib/determineTargetMediaLibrary'\nimport {findNdjsonEntry} from './lib/findNdjsonEntry'\n\ninterface ImportAssetsFlags {\n 'media-library-id'?: string\n 'replace-aspects'?: boolean\n}\n\nconst debug = baseDebug.extend('importMedia')\n\nconst DEFAULT_CONCURRENCY = 6\n\ninterface MediaLibraryUploadResult {\n asset: SanityDocument & {\n _type: 'sanity.asset'\n assetType: ImageAsset['_type'] | FileAsset['_type']\n aspects: unknown\n }\n assetInstance: ImageAsset | FileAsset\n}\n\ninterface MediaLibraryUploadResponse {\n type: 'response'\n body: MediaLibraryUploadResult\n}\n\ninterface ResolvedAsset {\n /**\n * The ids of the `sanity.asset` documents that currently refer to the asset.\n *\n * These documents contain aspects, and reference an asset instance document.\n */\n assetIds: string[]\n /**\n * The original filename of the asset as it appears in the import source.\n *\n * Note: Currently includes `images/` or `files/` prefix.\n */\n originalFilename: string\n sha1Hash: string\n isExistingAsset: boolean\n}\n\n/**\n * @internal\n */\nexport type AssetWithAspects<Asset extends ResolvedAsset = ResolvedAsset> = Asset & {\n aspects: unknown | undefined\n}\n\ninterface State {\n /**\n * The count of input files.\n */\n fileCount: number\n /**\n * The last asset processed.\n */\n asset: AssetWithAspects\n}\n\ninterface Options {\n sourcePath: string\n client: SanityClient\n replaceAspects: boolean\n chalk: Chalk\n spinner: ReturnType<CliCommandContext['output']['spinner']>\n output: CliOutputter\n}\n\ninterface Context extends Options {\n workingPath: string\n ndjson: () => ReadStream | null\n}\n\n// TODO: Order assets lexicographically before processing, allow resumable import\n// TODO: Granularly report upload progress of each asset (especially useful for large assets).\nconst importAssetsAction: CliCommandAction<ImportAssetsFlags> = async (args, context) => {\n const {output, apiClient, chalk} = context\n const [importSourcePath] = args.argsWithoutOptions\n const replaceAspects = args.extOptions['replace-aspects'] ?? false\n\n const mediaLibraryId =\n args.extOptions['media-library-id'] ?? (await determineTargetMediaLibrary(context))\n\n const client = apiClient().withConfig({\n 'apiVersion': MINIMUM_API_VERSION,\n 'requestTagPrefix': 'sanity.mediaLibraryCli.import',\n '~experimental_resource': {\n type: 'media-library',\n id: mediaLibraryId,\n },\n 'perspective': 'drafts',\n })\n\n output.print()\n output.print(`Importing to media library: ${chalk.bold(mediaLibraryId)}`)\n output.print(`Importing from path: ${chalk.bold(importSourcePath)}`)\n output.print()\n\n const spinner = output.spinner('Beginning import…').start()\n\n importer({\n client,\n sourcePath: importSourcePath,\n replaceAspects,\n chalk,\n spinner,\n output,\n })\n .pipe(\n reportResult({\n chalk,\n spinner,\n }),\n )\n .subscribe({\n error: (error) => {\n spinner.stop()\n output.error(error)\n },\n })\n}\n\nexport default importAssetsAction\n\nexport function importer(options: Options): Observable<State> {\n return resolveSource(options).pipe(\n mergeMap(({files, images, aspectsNdjsonPath, workingPath}) => {\n const fileCount = files.length + images.length\n\n if (fileCount === 0) {\n throw new Error('No assets to import')\n }\n\n const context: Context = {\n ...options,\n workingPath,\n ndjson: () => (aspectsNdjsonPath ? createReadStream(aspectsNdjsonPath) : null),\n }\n\n return from(files).pipe(\n switchMap((file) => zip(of<'file'>('file'), of(file))),\n mergeWith(from(images).pipe(switchMap((file) => zip(of<'image'>('image'), of(file))))),\n fetchExistingAssets(context),\n uploadAsset(context),\n resolveAspectData(context),\n setAspects(context),\n map((asset) => ({\n asset,\n fileCount,\n })),\n )\n }),\n )\n}\n\n/**\n * @internal\n */\nexport function resolveSource({\n sourcePath,\n chalk,\n}: Pick<Context, 'sourcePath' | 'chalk'>): Observable<{\n files: string[]\n images: string[]\n aspectsNdjsonPath: string\n workingPath: string\n}> {\n return from(fs.stat(sourcePath)).pipe(\n switchMap((stats) => {\n return stats.isDirectory()\n ? of(sourcePath)\n : from(mkdtemp(path.join(tmpdir(), 'sanity-media-library-import'))).pipe(\n switchMap((tempPath) => {\n return from(\n pipeline(createReadStream(sourcePath), gunzipMaybe(), untarMaybe(tempPath)),\n ).pipe(map(() => tempPath))\n }),\n )\n }),\n switchMap((importSourcePath) => {\n return from(\n glob(['**/data.ndjson'], {\n cwd: importSourcePath,\n deep: 2,\n absolute: true,\n }),\n ).pipe(\n map(([aspectsNdjsonPath]) => ({\n aspectsNdjsonPath,\n importSourcePath,\n workingPath:\n typeof aspectsNdjsonPath === 'undefined'\n ? importSourcePath\n : path.dirname(aspectsNdjsonPath),\n })),\n )\n }),\n tap(({aspectsNdjsonPath, importSourcePath}) => {\n if (typeof aspectsNdjsonPath === 'undefined') {\n debug(\n `[No data.ndjson file] No predefined aspect data will be imported from ${importSourcePath}`,\n )\n } else {\n debug(`[Found NDJSON file] ${aspectsNdjsonPath}`)\n }\n }),\n switchMap(({aspectsNdjsonPath, workingPath}) => {\n return from(\n Promise.all([\n glob(['files/*'], {\n cwd: workingPath,\n }),\n glob(['images/*'], {\n cwd: workingPath,\n }),\n ]),\n ).pipe(\n map(([files, images]) => ({\n files,\n images,\n aspectsNdjsonPath,\n workingPath,\n })),\n )\n }),\n )\n}\n\n/**\n * Untar the stream if its contents appear to be tarred.\n *\n * @internal\n */\nfunction untarMaybe(outputPath: string) {\n // @ts-expect-error `peek-stream` module currently untyped\n return peek({newline: false, maxBuffer: 300}, (data, swap) => {\n if (isTar(data)) {\n return swap(null, tar.extract(outputPath))\n }\n\n return swap(null)\n })\n}\n\n/**\n * Fetch the ids of all asset documents that reference the input asset.\n * The input asset is identified by its SHA-1 hash.\n *\n * @internal\n */\nfunction fetchAssetsByHash({\n client,\n type,\n}: {\n client: SanityClient\n type: 'image' | 'file'\n}): OperatorFunction<string, [hash: string, assetIds: string[]]> {\n return switchMap((hash) =>\n client.observable\n .fetch<string[]>(\n `*[\n _type == \"sanity.asset\" &&\n currentVersion._ref == *[\n _type == $type &&\n sha1hash == $hash\n ][0]._id\n ]._id`,\n {\n type: ['sanity', `${type}Asset`].join('.'),\n hash,\n },\n {\n tag: 'asset.getId',\n },\n )\n .pipe(switchMap((assetIds) => zip(of(hash), of(assetIds)))),\n )\n}\n\nfunction fetchExistingAssets({\n client,\n workingPath,\n}: Context): OperatorFunction<\n [type: 'image' | 'file', asset: string],\n ResolvedAsset | [type: 'image' | 'file', asset: string, hash: string]\n> {\n return mergeMap(([type, asset]) => {\n const createSha1Hash = createHash('sha1')\n\n const sha1hash = text(\n createReadStream(path.join(workingPath, asset)).pipe(createSha1Hash).setEncoding('hex'),\n )\n\n return from(sha1hash).pipe(\n tap((hash) => debug(`[Asset ${asset}] Checking for ${type} asset with hash ${hash}`)),\n fetchAssetsByHash({client, type}),\n map<\n [string, string[]],\n ResolvedAsset | [type: 'image' | 'file', asset: string, hash: string]\n >(([hash, assetIds]) => {\n if (assetIds.length === 0) {\n return [type, asset, hash]\n }\n\n return {\n originalFilename: asset,\n sha1Hash: hash,\n assetIds,\n isExistingAsset: true,\n }\n }),\n )\n })\n}\n\n/**\n * Find the first matching entry in the provided NDJSON stream and attach it to the asset object.\n *\n * @internal\n */\nfunction resolveAspectData({ndjson}: Context): OperatorFunction<ResolvedAsset, AssetWithAspects> {\n return mergeMap((resolvedAsset) => {\n const ndjsonStream = ndjson()\n\n // If no ndjson file exists, return asset with undefined aspects\n if (!ndjsonStream) {\n return of({\n ...resolvedAsset,\n aspects: undefined,\n })\n }\n\n return from(\n findNdjsonEntry<{aspects: unknown}>(\n ndjsonStream,\n (line) =>\n typeof line === 'object' &&\n line !== null &&\n 'filename' in line &&\n line.filename === resolvedAsset.originalFilename,\n ),\n ).pipe(\n map((aspectsFromImport) => ({\n ...resolvedAsset,\n aspects: aspectsFromImport?.aspects,\n })),\n )\n })\n}\n\n// TODO: Batch mutations to reduce HTTP request count.\nexport function setAspects({\n client,\n replaceAspects,\n}: Pick<Context, 'client' | 'replaceAspects'>): OperatorFunction<\n AssetWithAspects,\n AssetWithAspects\n> {\n return mergeMap((asset) => {\n const {assetIds, isExistingAsset, aspects} = asset\n\n if (isExistingAsset && !replaceAspects) {\n debug(`[Asset ${asset.originalFilename}] Skipping replacement of existing aspects`)\n return of(asset)\n }\n\n if (typeof aspects === 'undefined') {\n debug(`[Asset ${asset.originalFilename}] No aspects to import`)\n return of(asset)\n }\n\n const transaction = assetIds.reduce(\n (previous, assetId) => previous.patch(assetId, {set: {aspects}}),\n client.observable.transaction(),\n )\n\n debug(\n `[Asset ${asset.originalFilename}] Setting aspects on asset documents ${JSON.stringify(assetIds)}`,\n )\n\n return transaction\n .commit({\n visibility: 'async',\n tag: 'asset.setAspects',\n })\n .pipe(map(() => asset))\n }, DEFAULT_CONCURRENCY)\n}\n\nfunction uploadAsset({\n workingPath,\n client,\n}: Context): OperatorFunction<\n ResolvedAsset | [type: 'image' | 'file', asset: string, hash: string],\n ResolvedAsset\n> {\n return mergeMap((maybeResolvedAsset) => {\n if ('assetIds' in maybeResolvedAsset) {\n debug(\n `[Asset ${maybeResolvedAsset.originalFilename}] Skipping upload of existing asset with hash ${maybeResolvedAsset.sha1Hash}`,\n )\n return of(maybeResolvedAsset)\n }\n\n const [type, asset, hash] = maybeResolvedAsset\n debug(`[Asset ${asset}] Uploading new asset`)\n\n return client.observable.assets\n .upload(type, createReadStream(path.join(workingPath, asset)), {\n tag: 'asset.upload',\n })\n .pipe(\n catchError((error) => {\n // An asset matching the hash was not found during previous steps, but appears to exist upon upload.\n //\n // This may occur if:\n // - The asset was uploaded by another client since the check was performed.\n // - The asset instance document exists, but is not referenced by any asset document.\n if (error.statusCode === 409) {\n debug(`[Asset ${asset}] Cannot overwrite existing ${type} asset with hash ${hash}`)\n return EMPTY\n }\n return EMPTY\n }),\n filter((response) => response.type === 'response'),\n tap(() => debug(`[Asset ${asset}] Finished uploading new asset`)),\n // TODO: The `client.assets.upload` method should return `MediaLibraryUploadResponse` when operating on Media Library resources. When that occurs, this type assertion can be removed.\n map((response) => (response as unknown as MediaLibraryUploadResponse).body),\n map<MediaLibraryUploadResult, ResolvedAsset>((result) => ({\n assetIds: [result.asset._id],\n originalFilename: asset,\n sha1Hash: hash,\n isExistingAsset: false,\n })),\n )\n }, DEFAULT_CONCURRENCY)\n}\n\nfunction reportResult({\n chalk,\n spinner,\n}: Pick<Context, 'chalk' | 'spinner'>): OperatorFunction<State, [number, State | undefined]> {\n let previousState: State | undefined\n\n return pipe(\n scan<State, [number, State | undefined]>(\n (processedAssetsCount, state) => [processedAssetsCount[0] + 1, state],\n [0, undefined],\n ),\n tap({\n next: ([processedAssetsCount, state]) => {\n previousState = state\n spinner.text = `${processedAssetsCount} of ${state?.fileCount} assets imported ${chalk.dim(state?.asset.originalFilename)}`\n },\n complete: () => spinner.succeed(`Imported ${previousState?.fileCount} assets`),\n }),\n )\n}\n"],"names":["findNdjsonEntry","ndjson","matcher","lines","readline","createInterface","input","line","parsed","JSON","parse","trim","close","undefined","debug","baseDebug","extend","DEFAULT_CONCURRENCY","importAssetsAction","args","context","output","apiClient","chalk","importSourcePath","argsWithoutOptions","replaceAspects","extOptions","mediaLibraryId","determineTargetMediaLibrary","client","withConfig","MINIMUM_API_VERSION","type","id","print","bold","spinner","start","importer","sourcePath","pipe","reportResult","subscribe","error","stop","options","resolveSource","mergeMap","files","images","aspectsNdjsonPath","workingPath","fileCount","length","Error","createReadStream","from","switchMap","file","zip","of","mergeWith","fetchExistingAssets","uploadAsset","resolveAspectData","setAspects","map","asset","fs","stat","stats","isDirectory","mkdtemp","path","join","tmpdir","tempPath","pipeline","gunzipMaybe","untarMaybe","glob","cwd","deep","absolute","dirname","tap","Promise","all","outputPath","peek","newline","maxBuffer","data","swap","isTar","tar","extract","fetchAssetsByHash","hash","observable","fetch","tag","assetIds","createSha1Hash","createHash","sha1hash","text","setEncoding","originalFilename","sha1Hash","isExistingAsset","resolvedAsset","ndjsonStream","filename","aspectsFromImport","aspects","transaction","reduce","previous","assetId","patch","set","stringify","commit","visibility","maybeResolvedAsset","assets","upload","catchError","statusCode","EMPTY","filter","response","body","result","_id","previousState","scan","processedAssetsCount","state","next","dim","complete","succeed"],"mappings":"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"}
1
+ {"version":3,"file":"importAssetsAction.js","sources":["../../src/_internal/cli/actions/media/lib/findNdjsonEntry.ts","../../src/_internal/cli/actions/media/importAssetsAction.ts"],"sourcesContent":["import readline from 'node:readline'\nimport {Readable} from 'node:stream'\n\n/**\n * Find the first matching entry in the provided NDJSON stream.\n *\n * @internal\n */\nexport async function* findNdjsonEntry<Type>(\n ndjson: Readable,\n matcher: (line: Type) => boolean,\n): AsyncGenerator<Type | undefined> {\n const lines = readline.createInterface({\n input: ndjson,\n })\n\n try {\n for await (const line of lines) {\n const parsed = JSON.parse(line.trim())\n if (matcher(parsed)) {\n yield parsed\n return\n }\n }\n\n yield undefined\n } finally {\n lines.close()\n // Explicitly destroy the underlying stream to prevent file descriptor leaks\n ndjson.destroy()\n }\n}\n\n/**\n * Read and parse all entries from an NDJSON stream.\n *\n * @internal\n */\nexport async function readNdjsonFile<Type>(ndjson: Readable): Promise<Type[]> {\n const lines = readline.createInterface({\n input: ndjson,\n })\n\n const entries: Type[] = []\n\n try {\n for await (const line of lines) {\n const trimmed = line.trim()\n if (trimmed) {\n entries.push(JSON.parse(trimmed))\n }\n }\n } finally {\n lines.close()\n // Explicitly destroy the underlying stream to prevent file descriptor leaks\n ndjson.destroy()\n }\n\n return entries\n}\n","import {createHash} from 'node:crypto'\nimport {createReadStream} from 'node:fs'\nimport fs, {mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {text} from 'node:stream/consumers'\nimport {pipeline} from 'node:stream/promises'\n\nimport {\n type CliCommandAction,\n type CliCommandContext,\n type CliOutputter,\n type SanityClient,\n} from '@sanity/cli'\nimport {type FileAsset, type ImageAsset, type SanityDocument} from '@sanity/types'\nimport {type Chalk} from 'chalk'\nimport gunzipMaybe from 'gunzip-maybe'\nimport isTar from 'is-tar'\n// @ts-expect-error `peek-stream` module currently untyped\nimport peek from 'peek-stream'\nimport {\n catchError,\n EMPTY,\n filter,\n from,\n map,\n mergeMap,\n mergeWith,\n type Observable,\n of,\n type OperatorFunction,\n pipe,\n scan,\n switchMap,\n tap,\n zip,\n} from 'rxjs'\nimport tar from 'tar-fs'\nimport {glob} from 'tinyglobby'\n\nimport {debug as baseDebug} from '../../debug'\nimport {MINIMUM_API_VERSION} from './constants'\nimport {determineTargetMediaLibrary} from './lib/determineTargetMediaLibrary'\nimport {readNdjsonFile} from './lib/findNdjsonEntry'\n\ninterface ImportAssetsFlags {\n 'media-library-id'?: string\n 'replace-aspects'?: boolean\n}\n\nconst debug = baseDebug.extend('importMedia')\n\nconst DEFAULT_CONCURRENCY = 6\n\ninterface MediaLibraryUploadResult {\n asset: SanityDocument & {\n _type: 'sanity.asset'\n assetType: ImageAsset['_type'] | FileAsset['_type']\n aspects: unknown\n }\n assetInstance: ImageAsset | FileAsset\n}\n\ninterface MediaLibraryUploadResponse {\n type: 'response'\n body: MediaLibraryUploadResult\n}\n\ninterface ResolvedAsset {\n /**\n * The ids of the `sanity.asset` documents that currently refer to the asset.\n *\n * These documents contain aspects, and reference an asset instance document.\n */\n assetIds: string[]\n /**\n * The original filename of the asset as it appears in the import source.\n *\n * Note: Currently includes `images/` or `files/` prefix.\n */\n originalFilename: string\n sha1Hash: string\n isExistingAsset: boolean\n}\n\n/**\n * @internal\n */\nexport type AssetWithAspects<Asset extends ResolvedAsset = ResolvedAsset> = Asset & {\n aspects: unknown | undefined\n}\n\ninterface State {\n /**\n * The count of input files.\n */\n fileCount: number\n /**\n * The last asset processed.\n */\n asset: AssetWithAspects\n}\n\ninterface Options {\n sourcePath: string\n client: SanityClient\n replaceAspects: boolean\n chalk: Chalk\n spinner: ReturnType<CliCommandContext['output']['spinner']>\n output: CliOutputter\n}\n\ninterface AspectDataEntry {\n filename: string\n aspects?: unknown\n}\n\ninterface Context extends Options {\n workingPath: string\n aspectsData: AspectDataEntry[]\n}\n\n// TODO: Order assets lexicographically before processing, allow resumable import\n// TODO: Granularly report upload progress of each asset (especially useful for large assets).\nconst importAssetsAction: CliCommandAction<ImportAssetsFlags> = async (args, context) => {\n const {output, apiClient, chalk} = context\n const [importSourcePath] = args.argsWithoutOptions\n const replaceAspects = args.extOptions['replace-aspects'] ?? false\n\n const mediaLibraryId =\n args.extOptions['media-library-id'] ?? (await determineTargetMediaLibrary(context))\n\n const client = apiClient().withConfig({\n 'apiVersion': MINIMUM_API_VERSION,\n 'requestTagPrefix': 'sanity.mediaLibraryCli.import',\n '~experimental_resource': {\n type: 'media-library',\n id: mediaLibraryId,\n },\n 'perspective': 'drafts',\n })\n\n output.print()\n output.print(`Importing to media library: ${chalk.bold(mediaLibraryId)}`)\n output.print(`Importing from path: ${chalk.bold(importSourcePath)}`)\n output.print()\n\n const spinner = output.spinner('Beginning import…').start()\n\n importer({\n client,\n sourcePath: importSourcePath,\n replaceAspects,\n chalk,\n spinner,\n output,\n })\n .pipe(\n reportResult({\n chalk,\n spinner,\n }),\n )\n .subscribe({\n error: (error) => {\n spinner.stop()\n output.error(error)\n },\n })\n}\n\nexport default importAssetsAction\n\nexport function importer(options: Options): Observable<State> {\n return resolveSource(options).pipe(\n mergeMap(({files, images, aspectsNdjsonPath, workingPath}) => {\n const fileCount = files.length + images.length\n\n if (fileCount === 0) {\n throw new Error('No assets to import')\n }\n\n // Read the ndjson file once upfront and cache the data to avoid creating\n // multiple read streams (which causes file descriptor leaks)\n const aspectsDataPromise = aspectsNdjsonPath\n ? readNdjsonFile<AspectDataEntry>(createReadStream(aspectsNdjsonPath))\n : Promise.resolve([])\n\n return from(aspectsDataPromise).pipe(\n mergeMap((aspectsData) => {\n const context: Context = {\n ...options,\n workingPath,\n aspectsData,\n }\n\n return from(files).pipe(\n switchMap((file) => zip(of<'file'>('file'), of(file))),\n mergeWith(from(images).pipe(switchMap((file) => zip(of<'image'>('image'), of(file))))),\n fetchExistingAssets(context),\n uploadAsset(context),\n resolveAspectData(context),\n setAspects(context),\n map((asset) => ({\n asset,\n fileCount,\n })),\n )\n }),\n )\n }),\n )\n}\n\n/**\n * @internal\n */\nexport function resolveSource({\n sourcePath,\n chalk,\n}: Pick<Context, 'sourcePath' | 'chalk'>): Observable<{\n files: string[]\n images: string[]\n aspectsNdjsonPath: string\n workingPath: string\n}> {\n return from(fs.stat(sourcePath)).pipe(\n switchMap((stats) => {\n return stats.isDirectory()\n ? of(sourcePath)\n : from(mkdtemp(path.join(tmpdir(), 'sanity-media-library-import'))).pipe(\n switchMap((tempPath) => {\n return from(\n pipeline(createReadStream(sourcePath), gunzipMaybe(), untarMaybe(tempPath)),\n ).pipe(map(() => tempPath))\n }),\n )\n }),\n switchMap((importSourcePath) => {\n return from(\n glob(['**/data.ndjson'], {\n cwd: importSourcePath,\n deep: 2,\n absolute: true,\n }),\n ).pipe(\n map(([aspectsNdjsonPath]) => ({\n aspectsNdjsonPath,\n importSourcePath,\n workingPath:\n typeof aspectsNdjsonPath === 'undefined'\n ? importSourcePath\n : path.dirname(aspectsNdjsonPath),\n })),\n )\n }),\n tap(({aspectsNdjsonPath, importSourcePath}) => {\n if (typeof aspectsNdjsonPath === 'undefined') {\n debug(\n `[No data.ndjson file] No predefined aspect data will be imported from ${importSourcePath}`,\n )\n } else {\n debug(`[Found NDJSON file] ${aspectsNdjsonPath}`)\n }\n }),\n switchMap(({aspectsNdjsonPath, workingPath}) => {\n return from(\n Promise.all([\n glob(['files/*'], {\n cwd: workingPath,\n }),\n glob(['images/*'], {\n cwd: workingPath,\n }),\n ]),\n ).pipe(\n map(([files, images]) => ({\n files,\n images,\n aspectsNdjsonPath,\n workingPath,\n })),\n )\n }),\n )\n}\n\n/**\n * Untar the stream if its contents appear to be tarred.\n *\n * @internal\n */\nfunction untarMaybe(outputPath: string) {\n // @ts-expect-error `peek-stream` module currently untyped\n return peek({newline: false, maxBuffer: 300}, (data, swap) => {\n if (isTar(data)) {\n return swap(null, tar.extract(outputPath))\n }\n\n return swap(null)\n })\n}\n\n/**\n * Fetch the ids of all asset documents that reference the input asset.\n * The input asset is identified by its SHA-1 hash.\n *\n * @internal\n */\nfunction fetchAssetsByHash({\n client,\n type,\n}: {\n client: SanityClient\n type: 'image' | 'file'\n}): OperatorFunction<string, [hash: string, assetIds: string[]]> {\n return switchMap((hash) =>\n client.observable\n .fetch<string[]>(\n `*[\n _type == \"sanity.asset\" &&\n currentVersion._ref == *[\n _type == $type &&\n sha1hash == $hash\n ][0]._id\n ]._id`,\n {\n type: ['sanity', `${type}Asset`].join('.'),\n hash,\n },\n {\n tag: 'asset.getId',\n },\n )\n .pipe(switchMap((assetIds) => zip(of(hash), of(assetIds)))),\n )\n}\n\nfunction fetchExistingAssets({\n client,\n workingPath,\n}: Context): OperatorFunction<\n [type: 'image' | 'file', asset: string],\n ResolvedAsset | [type: 'image' | 'file', asset: string, hash: string]\n> {\n return mergeMap(([type, asset]) => {\n const createSha1Hash = createHash('sha1')\n\n const sha1hash = text(\n createReadStream(path.join(workingPath, asset)).pipe(createSha1Hash).setEncoding('hex'),\n )\n\n return from(sha1hash).pipe(\n tap((hash) => debug(`[Asset ${asset}] Checking for ${type} asset with hash ${hash}`)),\n fetchAssetsByHash({client, type}),\n map<\n [string, string[]],\n ResolvedAsset | [type: 'image' | 'file', asset: string, hash: string]\n >(([hash, assetIds]) => {\n if (assetIds.length === 0) {\n return [type, asset, hash]\n }\n\n return {\n originalFilename: asset,\n sha1Hash: hash,\n assetIds,\n isExistingAsset: true,\n }\n }),\n )\n })\n}\n\n/**\n * Find the matching entry in the cached aspect data and attach it to the asset object.\n *\n * @internal\n */\nfunction resolveAspectData({\n aspectsData,\n}: Context): OperatorFunction<ResolvedAsset, AssetWithAspects> {\n return map((resolvedAsset) => {\n // If no aspects data exists, return asset with undefined aspects\n if (!aspectsData || aspectsData.length === 0) {\n return {\n ...resolvedAsset,\n aspects: undefined,\n }\n }\n\n // Find matching aspect data from the cached data\n const aspectsFromImport = aspectsData.find(\n (entry) => entry.filename === resolvedAsset.originalFilename,\n )\n\n return {\n ...resolvedAsset,\n aspects: aspectsFromImport?.aspects,\n }\n })\n}\n\n// TODO: Batch mutations to reduce HTTP request count.\nexport function setAspects({\n client,\n replaceAspects,\n}: Pick<Context, 'client' | 'replaceAspects'>): OperatorFunction<\n AssetWithAspects,\n AssetWithAspects\n> {\n return mergeMap((asset) => {\n const {assetIds, isExistingAsset, aspects} = asset\n\n if (isExistingAsset && !replaceAspects) {\n debug(`[Asset ${asset.originalFilename}] Skipping replacement of existing aspects`)\n return of(asset)\n }\n\n if (typeof aspects === 'undefined') {\n debug(`[Asset ${asset.originalFilename}] No aspects to import`)\n return of(asset)\n }\n\n const transaction = assetIds.reduce(\n (previous, assetId) => previous.patch(assetId, {set: {aspects}}),\n client.observable.transaction(),\n )\n\n debug(\n `[Asset ${asset.originalFilename}] Setting aspects on asset documents ${JSON.stringify(assetIds)}`,\n )\n\n return transaction\n .commit({\n visibility: 'async',\n tag: 'asset.setAspects',\n })\n .pipe(map(() => asset))\n }, DEFAULT_CONCURRENCY)\n}\n\nfunction uploadAsset({\n workingPath,\n client,\n}: Context): OperatorFunction<\n ResolvedAsset | [type: 'image' | 'file', asset: string, hash: string],\n ResolvedAsset\n> {\n return mergeMap((maybeResolvedAsset) => {\n if ('assetIds' in maybeResolvedAsset) {\n debug(\n `[Asset ${maybeResolvedAsset.originalFilename}] Skipping upload of existing asset with hash ${maybeResolvedAsset.sha1Hash}`,\n )\n return of(maybeResolvedAsset)\n }\n\n const [type, asset, hash] = maybeResolvedAsset\n debug(`[Asset ${asset}] Uploading new asset`)\n\n return client.observable.assets\n .upload(type, createReadStream(path.join(workingPath, asset)), {\n tag: 'asset.upload',\n })\n .pipe(\n catchError((error) => {\n // An asset matching the hash was not found during previous steps, but appears to exist upon upload.\n //\n // This may occur if:\n // - The asset was uploaded by another client since the check was performed.\n // - The asset instance document exists, but is not referenced by any asset document.\n if (error.statusCode === 409) {\n debug(`[Asset ${asset}] Cannot overwrite existing ${type} asset with hash ${hash}`)\n return EMPTY\n }\n return EMPTY\n }),\n filter((response) => response.type === 'response'),\n tap(() => debug(`[Asset ${asset}] Finished uploading new asset`)),\n // TODO: The `client.assets.upload` method should return `MediaLibraryUploadResponse` when operating on Media Library resources. When that occurs, this type assertion can be removed.\n map((response) => (response as unknown as MediaLibraryUploadResponse).body),\n map<MediaLibraryUploadResult, ResolvedAsset>((result) => ({\n assetIds: [result.asset._id],\n originalFilename: asset,\n sha1Hash: hash,\n isExistingAsset: false,\n })),\n )\n }, DEFAULT_CONCURRENCY)\n}\n\nfunction reportResult({\n chalk,\n spinner,\n}: Pick<Context, 'chalk' | 'spinner'>): OperatorFunction<State, [number, State | undefined]> {\n let previousState: State | undefined\n\n return pipe(\n scan<State, [number, State | undefined]>(\n (processedAssetsCount, state) => [processedAssetsCount[0] + 1, state],\n [0, undefined],\n ),\n tap({\n next: ([processedAssetsCount, state]) => {\n previousState = state\n spinner.text = `${processedAssetsCount} of ${state?.fileCount} assets imported ${chalk.dim(state?.asset.originalFilename)}`\n },\n complete: () => spinner.succeed(`Imported ${previousState?.fileCount} assets`),\n }),\n )\n}\n"],"names":["readNdjsonFile","ndjson","lines","readline","createInterface","input","entries","line","trimmed","trim","push","JSON","parse","close","destroy","debug","baseDebug","extend","DEFAULT_CONCURRENCY","importAssetsAction","args","context","output","apiClient","chalk","importSourcePath","argsWithoutOptions","replaceAspects","extOptions","mediaLibraryId","determineTargetMediaLibrary","client","withConfig","MINIMUM_API_VERSION","type","id","print","bold","spinner","start","importer","sourcePath","pipe","reportResult","subscribe","error","stop","options","resolveSource","mergeMap","files","images","aspectsNdjsonPath","workingPath","fileCount","length","Error","aspectsDataPromise","createReadStream","Promise","resolve","from","aspectsData","switchMap","file","zip","of","mergeWith","fetchExistingAssets","uploadAsset","resolveAspectData","setAspects","map","asset","fs","stat","stats","isDirectory","mkdtemp","path","join","tmpdir","tempPath","pipeline","gunzipMaybe","untarMaybe","glob","cwd","deep","absolute","dirname","tap","all","outputPath","peek","newline","maxBuffer","data","swap","isTar","tar","extract","fetchAssetsByHash","hash","observable","fetch","tag","assetIds","createSha1Hash","createHash","sha1hash","text","setEncoding","originalFilename","sha1Hash","isExistingAsset","resolvedAsset","aspects","undefined","aspectsFromImport","find","entry","filename","transaction","reduce","previous","assetId","patch","set","stringify","commit","visibility","maybeResolvedAsset","assets","upload","catchError","statusCode","EMPTY","filter","response","body","result","_id","previousState","scan","processedAssetsCount","state","next","dim","complete","succeed"],"mappings":";;;;;;;;;;;;;;;;AAsCA,eAAsBA,eAAqBC,QAAmC;AAC5E,QAAMC,QAAQC,SAASC,gBAAgB;AAAA,IACrCC,OAAOJ;AAAAA,EAAAA,CACR,GAEKK,UAAkB,CAAA;AAExB,MAAI;AACF,qBAAiBC,QAAQL,OAAO;AAC9B,YAAMM,UAAUD,KAAKE,KAAAA;AACjBD,iBACFF,QAAQI,KAAKC,KAAKC,MAAMJ,OAAO,CAAC;AAAA,IAEpC;AAAA,EACF,UAAA;AACEN,UAAMW,MAAAA,GAENZ,OAAOa,QAAAA;AAAAA,EACT;AAEA,SAAOR;AACT;ACTA,MAAMS,QAAQC,QAAUC,OAAO,aAAa,GAEtCC,sBAAsB,GAwEtBC,qBAA0D,OAAOC,MAAMC,YAAY;AACvF,QAAM;AAAA,IAACC;AAAAA,IAAQC;AAAAA,IAAWC;AAAAA,EAAAA,IAASH,SAC7B,CAACI,gBAAgB,IAAIL,KAAKM,oBAC1BC,iBAAiBP,KAAKQ,WAAW,iBAAiB,KAAK,IAEvDC,iBACJT,KAAKQ,WAAW,kBAAkB,KAAM,MAAME,4BAA4BT,OAAO,GAE7EU,SAASR,UAAAA,EAAYS,WAAW;AAAA,IACpC,YAAcC;AAAAA,IACd,kBAAoB;AAAA,IACpB,0BAA0B;AAAA,MACxBC,MAAM;AAAA,MACNC,IAAIN;AAAAA,IAAAA;AAAAA,IAEN,aAAe;AAAA,EAAA,CAChB;AAEDP,SAAOc,SACPd,OAAOc,MAAM,+BAA+BZ,MAAMa,KAAKR,cAAc,CAAC,EAAE,GACxEP,OAAOc,MAAM,wBAAwBZ,MAAMa,KAAKZ,gBAAgB,CAAC,EAAE,GACnEH,OAAOc,MAAAA;AAEP,QAAME,UAAUhB,OAAOgB,QAAQ,wBAAmB,EAAEC,MAAAA;AAEpDC,WAAS;AAAA,IACPT;AAAAA,IACAU,YAAYhB;AAAAA,IACZE;AAAAA,IACAH;AAAAA,IACAc;AAAAA,IACAhB;AAAAA,EAAAA,CACD,EACEoB,KACCC,aAAa;AAAA,IACXnB;AAAAA,IACAc;AAAAA,EAAAA,CACD,CACH,EACCM,UAAU;AAAA,IACTC,OAAQA,CAAAA,UAAU;AAChBP,cAAQQ,KAAAA,GACRxB,OAAOuB,MAAMA,KAAK;AAAA,IACpB;AAAA,EAAA,CACD;AACL;AAIO,SAASL,SAASO,SAAqC;AAC5D,SAAOC,cAAcD,OAAO,EAAEL,KAC5BO,SAAS,CAAC;AAAA,IAACC;AAAAA,IAAOC;AAAAA,IAAQC;AAAAA,IAAmBC;AAAAA,EAAAA,MAAiB;AAC5D,UAAMC,YAAYJ,MAAMK,SAASJ,OAAOI;AAExC,QAAID,cAAc;AAChB,YAAM,IAAIE,MAAM,qBAAqB;AAKvC,UAAMC,qBAAqBL,oBACvBpD,eAAgC0D,iBAAiBN,iBAAiB,CAAC,IACnEO,QAAQC,QAAQ,EAAE;AAEtB,WAAOC,KAAKJ,kBAAkB,EAAEf,KAC9BO,SAAUa,CAAAA,gBAAgB;AACxB,YAAMzC,UAAmB;AAAA,QACvB,GAAG0B;AAAAA,QACHM;AAAAA,QACAS;AAAAA,MAAAA;AAGF,aAAOD,KAAKX,KAAK,EAAER,KACjBqB,UAAWC,CAAAA,SAASC,IAAIC,GAAW,MAAM,GAAGA,GAAGF,IAAI,CAAC,CAAC,GACrDG,UAAUN,KAAKV,MAAM,EAAET,KAAKqB,UAAWC,CAAAA,SAASC,IAAIC,GAAY,OAAO,GAAGA,GAAGF,IAAI,CAAC,CAAC,CAAC,CAAC,GACrFI,oBAAoB/C,OAAO,GAC3BgD,YAAYhD,OAAO,GACnBiD,kBAAkBjD,OAAO,GACzBkD,WAAWlD,OAAO,GAClBmD,IAAKC,CAAAA,WAAW;AAAA,QACdA;AAAAA,QACAnB;AAAAA,MAAAA,EACA,CACJ;AAAA,IACF,CAAC,CACH;AAAA,EACF,CAAC,CACH;AACF;AAKO,SAASN,cAAc;AAAA,EAC5BP;AAAAA,EACAjB;AACqC,GAKpC;AACD,SAAOqC,KAAKa,GAAGC,KAAKlC,UAAU,CAAC,EAAEC,KAC/BqB,UAAWa,CAAAA,UACFA,MAAMC,YAAAA,IACTX,GAAGzB,UAAU,IACboB,KAAKiB,QAAQC,KAAKC,KAAKC,UAAU,6BAA6B,CAAC,CAAC,EAAEvC,KAChEqB,UAAWmB,cACFrB,KACLsB,SAASzB,iBAAiBjB,UAAU,GAAG2C,YAAAA,GAAeC,WAAWH,QAAQ,CAAC,CAC5E,EAAExC,KAAK8B,IAAI,MAAMU,QAAQ,CAAC,CAC3B,CACH,CACL,GACDnB,UAAWtC,CAAAA,qBACFoC,KACLyB,KAAK,CAAC,gBAAgB,GAAG;AAAA,IACvBC,KAAK9D;AAAAA,IACL+D,MAAM;AAAA,IACNC,UAAU;AAAA,EAAA,CACX,CACH,EAAE/C,KACA8B,IAAI,CAAC,CAACpB,iBAAiB,OAAO;AAAA,IAC5BA;AAAAA,IACA3B;AAAAA,IACA4B,aACE,OAAOD,oBAAsB,MACzB3B,mBACAsD,KAAKW,QAAQtC,iBAAiB;AAAA,EAAA,EACpC,CACJ,CACD,GACDuC,IAAI,CAAC;AAAA,IAACvC;AAAAA,IAAmB3B;AAAAA,EAAAA,MAAsB;AAE3CV,UADE,OAAOqC,oBAAsB,MAE7B,yEAAyE3B,gBAAgB,KAGrF,uBAAuB2B,iBAAiB,EAF9C;AAAA,EAIJ,CAAC,GACDW,UAAU,CAAC;AAAA,IAACX;AAAAA,IAAmBC;AAAAA,EAAAA,MACtBQ,KACLF,QAAQiC,IAAI,CACVN,KAAK,CAAC,SAAS,GAAG;AAAA,IAChBC,KAAKlC;AAAAA,EAAAA,CACN,GACDiC,KAAK,CAAC,UAAU,GAAG;AAAA,IACjBC,KAAKlC;AAAAA,EAAAA,CACN,CAAC,CACH,CACH,EAAEX,KACA8B,IAAI,CAAC,CAACtB,OAAOC,MAAM,OAAO;AAAA,IACxBD;AAAAA,IACAC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,EAAAA,EACA,CACJ,CACD,CACH;AACF;AAOA,SAASgC,WAAWQ,YAAoB;AAEtC,SAAOC,KAAK;AAAA,IAACC,SAAS;AAAA,IAAOC,WAAW;AAAA,EAAA,GAAM,CAACC,MAAMC,SAC/CC,MAAMF,IAAI,IACLC,KAAK,MAAME,IAAIC,QAAQR,UAAU,CAAC,IAGpCK,KAAK,IAAI,CACjB;AACH;AAQA,SAASI,kBAAkB;AAAA,EACzBvE;AAAAA,EACAG;AAIF,GAAiE;AAC/D,SAAO6B,UAAWwC,CAAAA,SAChBxE,OAAOyE,WACJC,MACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAOA;AAAA,IACEvE,MAAM,CAAC,UAAU,GAAGA,IAAI,OAAO,EAAE8C,KAAK,GAAG;AAAA,IACzCuB;AAAAA,EAAAA,GAEF;AAAA,IACEG,KAAK;AAAA,EAAA,CAET,EACChE,KAAKqB,UAAW4C,cAAa1C,IAAIC,GAAGqC,IAAI,GAAGrC,GAAGyC,QAAQ,CAAC,CAAC,CAAC,CAC9D;AACF;AAEA,SAASvC,oBAAoB;AAAA,EAC3BrC;AAAAA,EACAsB;AACO,GAGP;AACA,SAAOJ,SAAS,CAAC,CAACf,MAAMuC,KAAK,MAAM;AACjC,UAAMmC,iBAAiBC,WAAW,MAAM,GAElCC,WAAWC,KACfrD,iBAAiBqB,KAAKC,KAAK3B,aAAaoB,KAAK,CAAC,EAAE/B,KAAKkE,cAAc,EAAEI,YAAY,KAAK,CACxF;AAEA,WAAOnD,KAAKiD,QAAQ,EAAEpE,KACpBiD,IAAKY,UAASxF,MAAM,UAAU0D,KAAK,kBAAkBvC,IAAI,oBAAoBqE,IAAI,EAAE,CAAC,GACpFD,kBAAkB;AAAA,MAACvE;AAAAA,MAAQG;AAAAA,IAAAA,CAAK,GAChCsC,IAGE,CAAC,CAAC+B,MAAMI,QAAQ,MACZA,SAASpD,WAAW,IACf,CAACrB,MAAMuC,OAAO8B,IAAI,IAGpB;AAAA,MACLU,kBAAkBxC;AAAAA,MAClByC,UAAUX;AAAAA,MACVI;AAAAA,MACAQ,iBAAiB;AAAA,IAAA,CAEpB,CACH;AAAA,EACF,CAAC;AACH;AAOA,SAAS7C,kBAAkB;AAAA,EACzBR;AACO,GAAsD;AAC7D,SAAOU,IAAK4C,CAAAA,kBAAkB;AAE5B,QAAI,CAACtD,eAAeA,YAAYP,WAAW;AACzC,aAAO;AAAA,QACL,GAAG6D;AAAAA,QACHC,SAASC;AAAAA,MAAAA;AAKb,UAAMC,oBAAoBzD,YAAY0D,KACnCC,WAAUA,MAAMC,aAAaN,cAAcH,gBAC9C;AAEA,WAAO;AAAA,MACL,GAAGG;AAAAA,MACHC,SAASE,mBAAmBF;AAAAA,IAAAA;AAAAA,EAEhC,CAAC;AACH;AAGO,SAAS9C,WAAW;AAAA,EACzBxC;AAAAA,EACAJ;AAC0C,GAG1C;AACA,SAAOsB,SAAUwB,CAAAA,UAAU;AACzB,UAAM;AAAA,MAACkC;AAAAA,MAAUQ;AAAAA,MAAiBE;AAAAA,IAAAA,IAAW5C;AAE7C,QAAI0C,mBAAmB,CAACxF;AACtBZ,aAAAA,MAAM,UAAU0D,MAAMwC,gBAAgB,4CAA4C,GAC3E/C,GAAGO,KAAK;AAGjB,QAAI,OAAO4C,UAAY;AACrBtG,aAAAA,MAAM,UAAU0D,MAAMwC,gBAAgB,wBAAwB,GACvD/C,GAAGO,KAAK;AAGjB,UAAMkD,cAAchB,SAASiB,OAC3B,CAACC,UAAUC,YAAYD,SAASE,MAAMD,SAAS;AAAA,MAACE,KAAK;AAAA,QAACX;AAAAA,MAAAA;AAAAA,IAAO,CAAE,GAC/DtF,OAAOyE,WAAWmB,aACpB;AAEA5G,WAAAA,MACE,UAAU0D,MAAMwC,gBAAgB,wCAAwCtG,KAAKsH,UAAUtB,QAAQ,CAAC,EAClG,GAEOgB,YACJO,OAAO;AAAA,MACNC,YAAY;AAAA,MACZzB,KAAK;AAAA,IAAA,CACN,EACAhE,KAAK8B,IAAI,MAAMC,KAAK,CAAC;AAAA,EAC1B,GAAGvD,mBAAmB;AACxB;AAEA,SAASmD,YAAY;AAAA,EACnBhB;AAAAA,EACAtB;AACO,GAGP;AACA,SAAOkB,SAAUmF,CAAAA,uBAAuB;AACtC,QAAI,cAAcA;AAChBrH,aAAAA,MACE,UAAUqH,mBAAmBnB,gBAAgB,iDAAiDmB,mBAAmBlB,QAAQ,EAC3H,GACOhD,GAAGkE,kBAAkB;AAG9B,UAAM,CAAClG,MAAMuC,OAAO8B,IAAI,IAAI6B;AAC5BrH,WAAAA,MAAM,UAAU0D,KAAK,uBAAuB,GAErC1C,OAAOyE,WAAW6B,OACtBC,OAAOpG,MAAMwB,iBAAiBqB,KAAKC,KAAK3B,aAAaoB,KAAK,CAAC,GAAG;AAAA,MAC7DiC,KAAK;AAAA,IAAA,CACN,EACAhE;AAAAA,MACC6F,WAAY1F,CAAAA,UAMNA,MAAM2F,eAAe,OACvBzH,MAAM,UAAU0D,KAAK,+BAA+BvC,IAAI,oBAAoBqE,IAAI,EAAE,GAC3EkC,SAEFA,KACR;AAAA,MACDC,OAAQC,CAAAA,aAAaA,SAASzG,SAAS,UAAU;AAAA,MACjDyD,IAAI,MAAM5E,MAAM,UAAU0D,KAAK,gCAAgC,CAAC;AAAA;AAAA,MAEhED,IAAKmE,CAAAA,aAAcA,SAAmDC,IAAI;AAAA,MAC1EpE,IAA8CqE,CAAAA,YAAY;AAAA,QACxDlC,UAAU,CAACkC,OAAOpE,MAAMqE,GAAG;AAAA,QAC3B7B,kBAAkBxC;AAAAA,QAClByC,UAAUX;AAAAA,QACVY,iBAAiB;AAAA,MAAA,EACjB;AAAA,IAAA;AAAA,EAER,GAAGjG,mBAAmB;AACxB;AAEA,SAASyB,aAAa;AAAA,EACpBnB;AAAAA,EACAc;AACkC,GAAyD;AAC3F,MAAIyG;AAEJ,SAAOrG,KACLsG,KACE,CAACC,sBAAsBC,UAAU,CAACD,qBAAqB,CAAC,IAAI,GAAGC,KAAK,GACpE,CAAC,GAAG5B,MAAS,CACf,GACA3B,IAAI;AAAA,IACFwD,MAAMA,CAAC,CAACF,sBAAsBC,KAAK,MAAM;AACvCH,sBAAgBG,OAChB5G,QAAQyE,OAAO,GAAGkC,oBAAoB,OAAOC,OAAO5F,SAAS,oBAAoB9B,MAAM4H,IAAIF,OAAOzE,MAAMwC,gBAAgB,CAAC;AAAA,IAC3H;AAAA,IACAoC,UAAUA,MAAM/G,QAAQgH,QAAQ,YAAYP,eAAezF,SAAS,SAAS;AAAA,EAAA,CAC9E,CACH;AACF;"}
@@ -1,4 +1,4 @@
1
- var version = "5.3.0-next.14+27686cb16d", peerDependencies = {
1
+ var version = "5.3.0-next.16+0e6cb2006d", peerDependencies = {
2
2
  "styled-components": "^6.1.15"
3
3
  };
4
4
  export {
@@ -7,7 +7,7 @@ try {
7
7
  try {
8
8
  buildVersion = buildVersion || // This is replaced by `@sanity/pkg-utils` at build time
9
9
  // and must always be references by its full static name, e.g. no optional chaining, no `if (process && process.env)` etc.
10
- "5.3.0-next.14+27686cb16d";
10
+ "5.3.0-next.16+0e6cb2006d";
11
11
  } catch {
12
12
  }
13
13
  const SANITY_VERSION = buildVersion || `${version}-dev`;
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
2
2
  import { c } from "react/compiler-runtime";
3
3
  import * as PathUtils from "@sanity/util/paths";
4
- import { toString, FOCUS_TERMINATOR, startsWith, isEqual as isEqual$3, pathFor, get as get$1, trimLeft, trimChildPath as trimChildPath$1, fromString } from "@sanity/util/paths";
4
+ import { toString, FOCUS_TERMINATOR, startsWith, isEqual as isEqual$3, pathFor, get as get$1, trimLeft, fromString, trimChildPath as trimChildPath$1 } from "@sanity/util/paths";
5
5
  import React, { forwardRef, useRef, useState, useId, useCallback, useMemo, useImperativeHandle, useEffect, isValidElement, Fragment, cloneElement, memo, useContext, useSyncExternalStore, Suspense, useReducer, startTransition, Component, useLayoutEffect, useEffectEvent, createContext, useDebugValue, PureComponent, Children, useTransition, useInsertionEffect, lazy, useDeferredValue, version, StrictMode } from "react";
6
6
  import deepEquals from "react-fast-compare";
7
7
  import { WorkspacesContext, LocaleContext, MediaLibraryIdsContext, PerspectiveContext, UserColorManagerContext, ResourceCacheContext, EventsContext, WorkspaceContext, DocumentChangeContext, ReviewChangesContext, DiffContext, PresenceContext, FormBuilderContext, ValidationContext, PortableTextMarkersContext, PortableTextMemberItemsContext, ChangeIndicatorTrackerContextStore, ChangeIndicatorTrackerContextGetSnapshot, FormCallbacksContext, ReferenceInputOptionsContext, DocumentIdContext, HoveredFieldContext, FieldActionsContext, FormValueContext, ReferenceItemRefContext, GetFormValueContext, EnhancedObjectDialogContext, DocumentFieldActionsContext, SortableItemIdContext, VirtualizerScrollInstanceContext, FullscreenPTEContext, PresenceTrackerContextStore, PresenceTrackerContextGetSnapshot, FormFieldPresenceContext, SourceContext, PortableTextMemberItemElementRefsContext, ScrollContext, AssetLimitUpsellContext, DialogStackContext, ReleasesUpsellContext, ReleasesMetadataContext, TableContext, SearchContext, SingleDocReleaseEnabledContext, SingleDocReleaseUpsellContext, SingleDocReleaseContext, ActiveWorkspaceMatcherContext, CalendarContext, AppIdCacheContext, CommentsAuthoringPathContext, CommentsIntentContext, CommentInputContext, CommentsContext, CommentsEnabledContext, CommentsOnboardingContext, CommentsSelectedPathContext, CommentsUpsellContext, AddonDatasetContext, SanityCreateConfigContext, ScheduledPublishingEnabledContext, SchedulesContext, SchedulePublishUpsellContext, DocumentActionPropsContext, TasksEnabledContext, IsLastPaneContext, MentionUserContext, TasksNavigationContext, TasksContext, TasksUpsellContext, RouterHistoryContext, ColorSchemeSetValueContext, ColorSchemeValueContext, DocumentLimitUpsellContext, NavbarContext, FreeTrialContext, LiveUserApplicationContext, PackageVersionInfoContext, StudioAnnouncementContext, CopyPasteContext, UserApplicationCacheContext, PreviewCardContext, ZIndexContext, zIndexContextDefaults } from "sanity/_singletons";
@@ -28048,7 +28048,15 @@ const TimeZoneButton = (props2) => {
28048
28048
  display: block;
28049
28049
  }
28050
28050
  }
28051
- `, Root$n = styled(Card)`
28051
+ `;
28052
+ function sanitizeTimeZoneKeyId(id2) {
28053
+ try {
28054
+ return fromString(id2).map((segment) => isKeySegment(segment) ? `key-${segment._key}` : typeof segment == "number" ? `idx-${segment}` : segment).join(".");
28055
+ } catch {
28056
+ return id2.replace(/[[\]="']/g, "-");
28057
+ }
28058
+ }
28059
+ const Root$n = styled(Card)`
28052
28060
  line-height: 1;
28053
28061
  `, serialize$2 = (date) => date.toISOString();
28054
28062
  function parseOptions$1(options = {}) {
@@ -28080,7 +28088,7 @@ function enforceTimeStep$1(dateString, timeStep) {
28080
28088
  return serialize$2(leftOver !== 0 ? setMinutes(date, minutes - leftOver) : date);
28081
28089
  }
28082
28090
  function DateTimeInput$2(props2) {
28083
- const $ = c(75), {
28091
+ const $ = c(77), {
28084
28092
  onChange,
28085
28093
  schemaType,
28086
28094
  value,
@@ -28117,64 +28125,67 @@ function DateTimeInput$2(props2) {
28117
28125
  const t4 = useFormValue(t3);
28118
28126
  let t5;
28119
28127
  $[3] !== t4 ? (t5 = getPublishedId(t4), $[3] = t4, $[4] = t5) : t5 = $[4];
28120
- const t6 = `${t5}.${id2}${allowTimeZoneSwitch ? "" : ".fixed"}`;
28121
- let t7;
28122
- $[5] !== value ? (t7 = value ? new Date(value) : void 0, $[5] = value, $[6] = t7) : t7 = $[6];
28128
+ const published = t5;
28129
+ let t6;
28130
+ $[5] !== id2 ? (t6 = sanitizeTimeZoneKeyId(id2), $[5] = id2, $[6] = t6) : t6 = $[6];
28131
+ const t7 = `${published}.${t6}${allowTimeZoneSwitch ? "" : ".fixed"}`;
28123
28132
  let t8;
28124
- $[7] !== displayTimeZone || $[8] !== t6 || $[9] !== t7 ? (t8 = {
28133
+ $[7] !== value ? (t8 = value ? new Date(value) : void 0, $[7] = value, $[8] = t8) : t8 = $[8];
28134
+ let t9;
28135
+ $[9] !== displayTimeZone || $[10] !== t7 || $[11] !== t8 ? (t9 = {
28125
28136
  type: "input",
28126
28137
  defaultTimeZone: displayTimeZone,
28127
- id: t6,
28128
- relativeDate: t7
28129
- }, $[7] = displayTimeZone, $[8] = t6, $[9] = t7, $[10] = t8) : t8 = $[10];
28130
- const timeZoneScope = t8, {
28138
+ id: t7,
28139
+ relativeDate: t8
28140
+ }, $[9] = displayTimeZone, $[10] = t7, $[11] = t8, $[12] = t9) : t9 = $[12];
28141
+ const timeZoneScope = t9, {
28131
28142
  timeZone
28132
28143
  } = useTimeZone(timeZoneScope);
28133
- let t9;
28134
- $[11] !== onChange || $[12] !== timeStep ? (t9 = (nextDate) => {
28144
+ let t10;
28145
+ $[13] !== onChange || $[14] !== timeStep ? (t10 = (nextDate) => {
28135
28146
  let date = nextDate;
28136
28147
  date !== null && timeStep > 1 && (date = enforceTimeStep$1(date, timeStep)), onChange(date === null ? unset() : set(date));
28137
- }, $[11] = onChange, $[12] = timeStep, $[13] = t9) : t9 = $[13];
28138
- const handleChange = t9;
28139
- let t10;
28140
- $[14] !== dateFormat || $[15] !== timeFormat || $[16] !== timeZone.name ? (t10 = (date_0) => format$1(date_0, `${dateFormat} ${timeFormat}`, {
28141
- timeZone: timeZone.name
28142
- }), $[14] = dateFormat, $[15] = timeFormat, $[16] = timeZone.name, $[17] = t10) : t10 = $[17];
28143
- const formatInputValue = t10;
28148
+ }, $[13] = onChange, $[14] = timeStep, $[15] = t10) : t10 = $[15];
28149
+ const handleChange = t10;
28144
28150
  let t11;
28145
- $[18] !== timeZone.name ? (t11 = getDeserializer(timeZone.name), $[18] = timeZone.name, $[19] = t11) : t11 = $[19];
28146
- const deserialize2 = t11;
28151
+ $[16] !== dateFormat || $[17] !== timeFormat || $[18] !== timeZone.name ? (t11 = (date_0) => format$1(date_0, `${dateFormat} ${timeFormat}`, {
28152
+ timeZone: timeZone.name
28153
+ }), $[16] = dateFormat, $[17] = timeFormat, $[18] = timeZone.name, $[19] = t11) : t11 = $[19];
28154
+ const formatInputValue = t11;
28147
28155
  let t12;
28148
- $[20] !== dateFormat || $[21] !== timeFormat || $[22] !== timeZone.name ? (t12 = (inputValue) => parse$2(inputValue, `${dateFormat} ${timeFormat}`, timeZone.name), $[20] = dateFormat, $[21] = timeFormat, $[22] = timeZone.name, $[23] = t12) : t12 = $[23];
28149
- const parseInputValue = t12;
28156
+ $[20] !== timeZone.name ? (t12 = getDeserializer(timeZone.name), $[20] = timeZone.name, $[21] = t12) : t12 = $[21];
28157
+ const deserialize2 = t12;
28150
28158
  let t13;
28151
- $[24] !== t ? (t13 = getCalendarLabels(t), $[24] = t, $[25] = t13) : t13 = $[25];
28152
- const calendarLabels = t13, t14 = `field-${id2}`, t15 = !!focused;
28153
- let t16;
28154
- $[26] !== allowTimeZoneSwitch || $[27] !== displayTimeZone || $[28] !== t || $[29] !== timeZone.alternativeName || $[30] !== timeZone.offset || $[31] !== timeZoneScope || $[32] !== title ? (t16 = displayTimeZone && /* @__PURE__ */ jsx(TimeZoneButtonElementQuery$1, { children: /* @__PURE__ */ jsx(TimeZoneButton, { tooltipContent: /* @__PURE__ */ jsx(Translate, { t, i18nKey: "time-zone.time-zone-tooltip-input", values: {
28159
+ $[22] !== dateFormat || $[23] !== timeFormat || $[24] !== timeZone.name ? (t13 = (inputValue) => parse$2(inputValue, `${dateFormat} ${timeFormat}`, timeZone.name), $[22] = dateFormat, $[23] = timeFormat, $[24] = timeZone.name, $[25] = t13) : t13 = $[25];
28160
+ const parseInputValue = t13;
28161
+ let t14;
28162
+ $[26] !== t ? (t14 = getCalendarLabels(t), $[26] = t, $[27] = t14) : t14 = $[27];
28163
+ const calendarLabels = t14, t15 = `field-${id2}`, t16 = !!focused;
28164
+ let t17;
28165
+ $[28] !== allowTimeZoneSwitch || $[29] !== displayTimeZone || $[30] !== t || $[31] !== timeZone.alternativeName || $[32] !== timeZone.offset || $[33] !== timeZoneScope || $[34] !== title ? (t17 = displayTimeZone && /* @__PURE__ */ jsx(TimeZoneButtonElementQuery$1, { children: /* @__PURE__ */ jsx(TimeZoneButton, { tooltipContent: /* @__PURE__ */ jsx(Translate, { t, i18nKey: "time-zone.time-zone-tooltip-input", values: {
28155
28166
  title,
28156
28167
  alternativeName: timeZone.alternativeName,
28157
28168
  offset: timeZone.offset
28158
- } }), allowTimeZoneSwitch, useElementQueries: !0, timeZoneScope }) }), $[26] = allowTimeZoneSwitch, $[27] = displayTimeZone, $[28] = t, $[29] = timeZone.alternativeName, $[30] = timeZone.offset, $[31] = timeZoneScope, $[32] = title, $[33] = t16) : t16 = $[33];
28159
- let t17;
28160
- $[34] !== id2 || $[35] !== schemaType.deprecated || $[36] !== schemaType.description || $[37] !== schemaType.title || $[38] !== t16 || $[39] !== validation2 ? (t17 = /* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsx(FormFieldHeaderText, { deprecated: schemaType.deprecated, description: schemaType.description, inputId: id2, validation: validation2, title: schemaType.title, suffix: t16 }) }), $[34] = id2, $[35] = schemaType.deprecated, $[36] = schemaType.description, $[37] = schemaType.title, $[38] = t16, $[39] = validation2, $[40] = t17) : t17 = $[40];
28169
+ } }), allowTimeZoneSwitch, useElementQueries: !0, timeZoneScope }) }), $[28] = allowTimeZoneSwitch, $[29] = displayTimeZone, $[30] = t, $[31] = timeZone.alternativeName, $[32] = timeZone.offset, $[33] = timeZoneScope, $[34] = title, $[35] = t17) : t17 = $[35];
28161
28170
  let t18;
28162
- $[41] !== actions || $[42] !== comments2 || $[43] !== hovered || $[44] !== id2 || $[45] !== presence || $[46] !== slot || $[47] !== t15 || $[48] !== t17 ? (t18 = /* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, children: /* @__PURE__ */ jsx(FormFieldBaseHeader, { __internal_comments: comments2, __internal_slot: slot, actions, fieldFocused: t15, fieldHovered: hovered, presence, inputId: id2, content: t17 }) }), $[41] = actions, $[42] = comments2, $[43] = hovered, $[44] = id2, $[45] = presence, $[46] = slot, $[47] = t15, $[48] = t17, $[49] = t18) : t18 = $[49];
28171
+ $[36] !== id2 || $[37] !== schemaType.deprecated || $[38] !== schemaType.description || $[39] !== schemaType.title || $[40] !== t17 || $[41] !== validation2 ? (t18 = /* @__PURE__ */ jsx(Stack, { space: 2, children: /* @__PURE__ */ jsx(FormFieldHeaderText, { deprecated: schemaType.deprecated, description: schemaType.description, inputId: id2, validation: validation2, title: schemaType.title, suffix: t17 }) }), $[36] = id2, $[37] = schemaType.deprecated, $[38] = schemaType.description, $[39] = schemaType.title, $[40] = t17, $[41] = validation2, $[42] = t18) : t18 = $[42];
28163
28172
  let t19;
28164
- $[50] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t19 = /* @__PURE__ */ jsx(FormFieldStatus, { maxAvatars: 1, position: "top" }), $[50] = t19) : t19 = $[50];
28165
- const t20 = !!focused;
28166
- let t21;
28167
- $[51] !== calendarLabels || $[52] !== deserialize2 || $[53] !== elementProps || $[54] !== formatInputValue || $[55] !== handleChange || $[56] !== parseInputValue || $[57] !== schemaType.placeholder || $[58] !== timeStep || $[59] !== timeZoneScope || $[60] !== value ? (t21 = /* @__PURE__ */ jsx("div", { "data-testid": "change-bar-wrapper", children: /* @__PURE__ */ jsx("div", { "data-testid": "change-bar__field-wrapper", children: /* @__PURE__ */ jsx(CommonDateTimeInput$1, { ...elementProps, calendarLabels, deserialize: deserialize2, formatInputValue, onChange: handleChange, parseInputValue, placeholder: schemaType.placeholder, serialize: serialize$2, timeStep, selectTime: !0, value, timeZoneScope }) }) }), $[51] = calendarLabels, $[52] = deserialize2, $[53] = elementProps, $[54] = formatInputValue, $[55] = handleChange, $[56] = parseInputValue, $[57] = schemaType.placeholder, $[58] = timeStep, $[59] = timeZoneScope, $[60] = value, $[61] = t21) : t21 = $[61];
28173
+ $[43] !== actions || $[44] !== comments2 || $[45] !== hovered || $[46] !== id2 || $[47] !== presence || $[48] !== slot || $[49] !== t16 || $[50] !== t18 ? (t19 = /* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, children: /* @__PURE__ */ jsx(FormFieldBaseHeader, { __internal_comments: comments2, __internal_slot: slot, actions, fieldFocused: t16, fieldHovered: hovered, presence, inputId: id2, content: t18 }) }), $[43] = actions, $[44] = comments2, $[45] = hovered, $[46] = id2, $[47] = presence, $[48] = slot, $[49] = t16, $[50] = t18, $[51] = t19) : t19 = $[51];
28174
+ let t20;
28175
+ $[52] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (t20 = /* @__PURE__ */ jsx(FormFieldStatus, { maxAvatars: 1, position: "top" }), $[52] = t20) : t20 = $[52];
28176
+ const t21 = !!focused;
28168
28177
  let t22;
28169
- $[62] !== changed || $[63] !== path || $[64] !== t20 || $[65] !== t21 ? (t22 = /* @__PURE__ */ jsx(ChangeIndicator, { hasFocus: t20, isChanged: changed, path, children: t21 }), $[62] = changed, $[63] = path, $[64] = t20, $[65] = t21, $[66] = t22) : t22 = $[66];
28178
+ $[53] !== calendarLabels || $[54] !== deserialize2 || $[55] !== elementProps || $[56] !== formatInputValue || $[57] !== handleChange || $[58] !== parseInputValue || $[59] !== schemaType.placeholder || $[60] !== timeStep || $[61] !== timeZoneScope || $[62] !== value ? (t22 = /* @__PURE__ */ jsx("div", { "data-testid": "change-bar-wrapper", children: /* @__PURE__ */ jsx("div", { "data-testid": "change-bar__field-wrapper", children: /* @__PURE__ */ jsx(CommonDateTimeInput$1, { ...elementProps, calendarLabels, deserialize: deserialize2, formatInputValue, onChange: handleChange, parseInputValue, placeholder: schemaType.placeholder, serialize: serialize$2, timeStep, selectTime: !0, value, timeZoneScope }) }) }), $[53] = calendarLabels, $[54] = deserialize2, $[55] = elementProps, $[56] = formatInputValue, $[57] = handleChange, $[58] = parseInputValue, $[59] = schemaType.placeholder, $[60] = timeStep, $[61] = timeZoneScope, $[62] = value, $[63] = t22) : t22 = $[63];
28170
28179
  let t23;
28171
- $[67] !== t18 || $[68] !== t22 ? (t23 = /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
28172
- t18,
28173
- t19,
28174
- t22
28175
- ] }), $[67] = t18, $[68] = t22, $[69] = t23) : t23 = $[69];
28180
+ $[64] !== changed || $[65] !== path || $[66] !== t21 || $[67] !== t22 ? (t23 = /* @__PURE__ */ jsx(ChangeIndicator, { hasFocus: t21, isChanged: changed, path, children: t22 }), $[64] = changed, $[65] = path, $[66] = t21, $[67] = t22, $[68] = t23) : t23 = $[68];
28176
28181
  let t24;
28177
- return $[70] !== onMouseEnter || $[71] !== onMouseLeave || $[72] !== t14 || $[73] !== t23 ? (t24 = /* @__PURE__ */ jsx(Root$n, { onMouseEnter, onMouseLeave, "data-testid": t14, radius: 2, children: t23 }), $[70] = onMouseEnter, $[71] = onMouseLeave, $[72] = t14, $[73] = t23, $[74] = t24) : t24 = $[74], t24;
28182
+ $[69] !== t19 || $[70] !== t23 ? (t24 = /* @__PURE__ */ jsxs(Flex, { direction: "column", children: [
28183
+ t19,
28184
+ t20,
28185
+ t23
28186
+ ] }), $[69] = t19, $[70] = t23, $[71] = t24) : t24 = $[71];
28187
+ let t25;
28188
+ return $[72] !== onMouseEnter || $[73] !== onMouseLeave || $[74] !== t15 || $[75] !== t24 ? (t25 = /* @__PURE__ */ jsx(Root$n, { onMouseEnter, onMouseLeave, "data-testid": t15, radius: 2, children: t24 }), $[72] = onMouseEnter, $[73] = onMouseLeave, $[74] = t15, $[75] = t24, $[76] = t25) : t25 = $[76], t25;
28178
28189
  }
28179
28190
  function EmailInput(props2) {
28180
28191
  const $ = c(3), {