instant-cli 1.0.60 → 1.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/__tests__/backupDownload.test.ts +206 -0
  3. package/__tests__/backups.test.ts +221 -0
  4. package/dist/commands/backup/download.d.ts +10 -0
  5. package/dist/commands/backup/download.d.ts.map +1 -0
  6. package/dist/commands/backup/download.js +174 -0
  7. package/dist/commands/backup/download.js.map +1 -0
  8. package/dist/commands/backup/list.d.ts +11 -0
  9. package/dist/commands/backup/list.d.ts.map +1 -0
  10. package/dist/commands/backup/list.js +74 -0
  11. package/dist/commands/backup/list.js.map +1 -0
  12. package/dist/index.d.ts +9 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +33 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/lib/backupDownload.d.ts +21 -0
  17. package/dist/lib/backupDownload.d.ts.map +1 -0
  18. package/dist/lib/backupDownload.js +113 -0
  19. package/dist/lib/backupDownload.js.map +1 -0
  20. package/dist/lib/backups.d.ts +12 -0
  21. package/dist/lib/backups.d.ts.map +1 -0
  22. package/dist/lib/backups.js +26 -0
  23. package/dist/lib/backups.js.map +1 -0
  24. package/dist/lib/platformApi.d.ts +5 -0
  25. package/dist/lib/platformApi.d.ts.map +1 -0
  26. package/dist/lib/platformApi.js +11 -0
  27. package/dist/lib/platformApi.js.map +1 -0
  28. package/dist/lib/webhooks.d.ts +4 -5
  29. package/dist/lib/webhooks.d.ts.map +1 -1
  30. package/dist/lib/webhooks.js +2 -9
  31. package/dist/lib/webhooks.js.map +1 -1
  32. package/dist/ui/lib.d.ts +1 -1
  33. package/dist/ui/lib.d.ts.map +1 -1
  34. package/dist/ui/lib.js.map +1 -1
  35. package/package.json +5 -4
  36. package/src/commands/backup/download.ts +231 -0
  37. package/src/commands/backup/list.ts +94 -0
  38. package/src/index.ts +60 -0
  39. package/src/lib/backupDownload.ts +145 -0
  40. package/src/lib/backups.ts +33 -0
  41. package/src/lib/platformApi.ts +11 -0
  42. package/src/lib/webhooks.ts +1 -10
  43. package/src/ui/lib.ts +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backupDownload.js","sourceRoot":"","sources":["../../src/lib/backupDownload.ts"],"names":[],"mappings":"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","sourcesContent":["import { createWriteStream } from 'node:fs';\nimport { open, rename, unlink } from 'node:fs/promises';\nimport { randomBytes } from 'node:crypto';\nimport { once } from 'node:events';\nimport { get as httpGet, type IncomingMessage } from 'node:http';\nimport { get as httpsGet } from 'node:https';\nimport { Readable, Writable, type Duplex } from 'node:stream';\nimport zlib from 'node:zlib';\nimport type {\n AppBackup,\n BackupArchiveWriter,\n BackupDownloadProgress,\n BackupDownloadResult,\n BackupsManager,\n} from '@instantdb/platform';\n\nexport type {\n BackupDownloadProgress,\n BackupDownloadResult,\n} from '@instantdb/platform';\n\n// zstd landed in node:zlib in 22.15 / 23.8; on older Nodes the property is\n// absent, so feature-detect instead of assuming the type declarations match\n// the runtime.\nconst createZstdDecompress: (() => Duplex) | undefined = (\n zlib as { createZstdDecompress?: () => Duplex }\n).createZstdDecompress;\n\nfunction fetchStream(\n url: string,\n signal: AbortSignal,\n): Promise<IncomingMessage> {\n return new Promise((resolve, reject) => {\n const get = url.startsWith('https:') ? httpsGet : httpGet;\n const req = get(url, { signal }, resolve);\n req.on('error', reject);\n });\n}\n\n// .pipe doesn't forward errors, so a source failure would otherwise leave the\n// destination (and the zip writer reading from it) hanging forever.\nfunction pipe(src: Readable, dst: Duplex): Duplex {\n src.on('error', (e) => dst.destroy(e));\n return src.pipe(dst);\n}\n\n// Fetches a presigned URL with node:http(s), decompressing explicitly: the\n// entity shards are served with `Content-Encoding: zstd` and Node doesn't\n// auto-decompress that. downloadBackupToFile refuses to run without zstd\n// support, so the assertion below can't fire.\nasync function fetchBody(\n url: string,\n signal: AbortSignal,\n): Promise<ReadableStream<Uint8Array>> {\n const res = await fetchStream(url, signal);\n if (res.statusCode !== 200) {\n res.resume();\n throw new Error(`HTTP ${res.statusCode}`);\n }\n const encoding = res.headers['content-encoding'];\n let stream: Readable = res;\n if (encoding === 'zstd') {\n stream = pipe(stream, createZstdDecompress!());\n } else if (encoding === 'gzip') {\n stream = pipe(stream, zlib.createGunzip());\n } else if (encoding) {\n res.destroy();\n throw new Error(`Unsupported content encoding: ${encoding}`);\n }\n return Readable.toWeb(stream) as ReadableStream<Uint8Array>;\n}\n\nasync function createZipWriter(\n sink: WritableStream<Uint8Array>,\n signal: AbortSignal,\n): Promise<BackupArchiveWriter> {\n // Loaded on demand so every other CLI command skips parsing it.\n const { ZipWriter } = await import('@zip.js/zip.js');\n // zip64: without it any archive whose central-directory offset passes 4GB\n // writes a wrapped 32-bit offset and the zip is unreadable.\n return new ZipWriter(sink, { zip64: true, signal });\n}\n\n/**\n * Downloads a backup into a zip file at `outPath` via the shared\n * `BackupsManager.downloadArchive` pipeline, supplying the Node-specific\n * pieces:\n * presigned URLs are fetched with node:http(s) and decompressed explicitly,\n * and the archive streams to disk with backpressure so memory stays flat\n * regardless of backup size.\n *\n * Writes to `<outPath>.partial` and renames on success; a failed or aborted\n * download removes the partial file.\n */\nexport async function downloadBackupToFile(opts: {\n manager: BackupsManager;\n backup: AppBackup;\n outPath: string;\n signal: AbortSignal;\n onProgress: (progress: BackupDownloadProgress) => void;\n}): Promise<BackupDownloadResult> {\n // The entity shards are served with `Content-Encoding: zstd`; fail before\n // writing anything if this Node can't decompress them.\n if (!createZstdDecompress) {\n throw new Error(\n 'Downloading backups requires Node 22.15 or newer (for zstd support).',\n );\n }\n\n // Randomized so a stale partial or a concurrent download of the same\n // backup can't collide; 'wx' turns any remaining collision into an error\n // instead of silently truncating another run's file.\n const partialPath = `${opts.outPath}.partial-${randomBytes(4).toString('hex')}`;\n const fileStream = createWriteStream(partialPath, { flags: 'wx' });\n const awaitFileClosed = async () => {\n if (!fileStream.closed) await once(fileStream, 'close');\n };\n try {\n const result = await opts.manager.downloadArchive({\n backup: opts.backup,\n fetchBody,\n sink: Writable.toWeb(fileStream) as WritableStream<Uint8Array>,\n createWriter: createZipWriter,\n signal: opts.signal,\n onProgress: opts.onProgress,\n });\n await awaitFileClosed();\n // Flush to disk before the rename so a crash right after can't leave a\n // complete-looking zip with unwritten tails.\n const fh = await open(partialPath, 'r+');\n try {\n await fh.sync();\n } finally {\n await fh.close();\n }\n await rename(partialPath, opts.outPath);\n return result;\n } catch (e) {\n // The pipeline already aborted the sink; wait for the fd to close, then\n // discard the partial file on disk.\n await awaitFileClosed().catch(() => {});\n await unlink(partialPath).catch(() => {});\n throw e;\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { Effect } from 'effect';
2
+ import type { BackupsManager } from '@instantdb/platform';
3
+ import { CurrentApp } from '../context/currentApp.ts';
4
+ import { PlatformApiError } from '../context/platformApi.ts';
5
+ export declare const useBackupsManager: <R>(fun: (manager: BackupsManager) => Promise<R>, errorMessage?: string) => Effect.Effect<R, import("../errors.ts").BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError | PlatformApiError, import("../context/authToken.ts").AuthToken | CurrentApp>;
6
+ /**
7
+ * Yields a `BackupsManager` instance scoped to the current app. Use when you
8
+ * need to hold on to the manager outside an Effect (e.g. to drive the
9
+ * long-running download pipeline).
10
+ */
11
+ export declare const buildBackupsManager: Effect.Effect<BackupsManager, import("../errors.ts").BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, import("../context/authToken.ts").AuthToken | CurrentApp>;
12
+ //# sourceMappingURL=backups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backups.d.ts","sourceRoot":"","sources":["../../src/lib/backups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG7D,eAAO,MAAM,iBAAiB,GAAI,CAAC,EACjC,KAAK,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,EAC5C,eAAe,MAAM,4NAanB,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,mNAI9B,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { Effect } from 'effect';
2
+ import { CurrentApp } from "../context/currentApp.js";
3
+ import { PlatformApiError } from "../context/platformApi.js";
4
+ import { getAuthedPlatformApi } from "./platformApi.js";
5
+ export const useBackupsManager = (fun, errorMessage) => Effect.gen(function* () {
6
+ const api = yield* getAuthedPlatformApi;
7
+ const { appId } = yield* CurrentApp;
8
+ return yield* Effect.tryPromise({
9
+ try: () => fun(api.backups(appId)),
10
+ catch: (e) => new PlatformApiError({
11
+ message: errorMessage ?? 'Error using backups api',
12
+ cause: e,
13
+ }),
14
+ });
15
+ });
16
+ /**
17
+ * Yields a `BackupsManager` instance scoped to the current app. Use when you
18
+ * need to hold on to the manager outside an Effect (e.g. to drive the
19
+ * long-running download pipeline).
20
+ */
21
+ export const buildBackupsManager = Effect.gen(function* () {
22
+ const api = yield* getAuthedPlatformApi;
23
+ const { appId } = yield* CurrentApp;
24
+ return api.backups(appId);
25
+ });
26
+ //# sourceMappingURL=backups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backups.js","sourceRoot":"","sources":["../../src/lib/backups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,GAA4C,EAC5C,YAAqB,EACrB,EAAE,CACF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IACpC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QAC9B,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAClC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACX,IAAI,gBAAgB,CAAC;YACnB,OAAO,EAAE,YAAY,IAAI,yBAAyB;YAClD,KAAK,EAAE,CAAC;SACT,CAAC;KACL,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACrD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IACpC,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC","sourcesContent":["import { Effect } from 'effect';\nimport type { BackupsManager } from '@instantdb/platform';\nimport { CurrentApp } from '../context/currentApp.ts';\nimport { PlatformApiError } from '../context/platformApi.ts';\nimport { getAuthedPlatformApi } from './platformApi.ts';\n\nexport const useBackupsManager = <R>(\n fun: (manager: BackupsManager) => Promise<R>,\n errorMessage?: string,\n) =>\n Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n return yield* Effect.tryPromise({\n try: () => fun(api.backups(appId)),\n catch: (e) =>\n new PlatformApiError({\n message: errorMessage ?? 'Error using backups api',\n cause: e,\n }),\n });\n });\n\n/**\n * Yields a `BackupsManager` instance scoped to the current app. Use when you\n * need to hold on to the manager outside an Effect (e.g. to drive the\n * long-running download pipeline).\n */\nexport const buildBackupsManager = Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n return api.backups(appId);\n});\n"]}
@@ -0,0 +1,5 @@
1
+ import { Effect } from 'effect';
2
+ import { PlatformApi as InstantPlatformApi } from '@instantdb/platform';
3
+ import { AuthToken } from '../context/authToken.ts';
4
+ export declare const getAuthedPlatformApi: Effect.Effect<InstantPlatformApi, import("../errors.ts").BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, AuthToken>;
5
+ //# sourceMappingURL=platformApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platformApi.d.ts","sourceRoot":"","sources":["../../src/lib/platformApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGpD,eAAO,MAAM,oBAAoB,wKAK/B,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Effect } from 'effect';
2
+ import { PlatformApi as InstantPlatformApi } from '@instantdb/platform';
3
+ import { AuthToken } from "../context/authToken.js";
4
+ import { getBaseUrl } from "./config.js";
5
+ export const getAuthedPlatformApi = Effect.gen(function* () {
6
+ const apiURI = yield* getBaseUrl;
7
+ const authToken = yield* AuthToken;
8
+ const token = yield* authToken.getAuthToken;
9
+ return new InstantPlatformApi({ apiURI, auth: { token } });
10
+ });
11
+ //# sourceMappingURL=platformApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platformApi.js","sourceRoot":"","sources":["../../src/lib/platformApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IACjC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC;IAC5C,OAAO,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC,CAAC,CAAC","sourcesContent":["import { Effect } from 'effect';\nimport { PlatformApi as InstantPlatformApi } from '@instantdb/platform';\nimport { AuthToken } from '../context/authToken.ts';\nimport { getBaseUrl } from './config.ts';\n\nexport const getAuthedPlatformApi = Effect.gen(function* () {\n const apiURI = yield* getBaseUrl;\n const authToken = yield* AuthToken;\n const token = yield* authToken.getAuthToken;\n return new InstantPlatformApi({ apiURI, auth: { token } });\n});\n"]}
@@ -1,28 +1,27 @@
1
1
  import { Effect } from 'effect';
2
2
  import { type WebhookAction, type WebhookEventInfo, type WebhooksManager } from '@instantdb/platform';
3
- import { AuthToken } from '../context/authToken.ts';
4
3
  import { CurrentApp } from '../context/currentApp.ts';
5
4
  import { PlatformApiError } from '../context/platformApi.ts';
6
5
  import { BadArgsError } from '../errors.ts';
7
6
  export declare const WEBHOOK_ACTIONS: readonly WebhookAction[];
8
- export declare const useWebhooksManager: <R>(fun: (manager: WebhooksManager<any>) => Promise<R>, errorMessage?: string) => Effect.Effect<R, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError | PlatformApiError, AuthToken | CurrentApp>;
7
+ export declare const useWebhooksManager: <R>(fun: (manager: WebhooksManager<any>) => Promise<R>, errorMessage?: string) => Effect.Effect<R, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError | PlatformApiError, import("../context/authToken.ts").AuthToken | CurrentApp>;
9
8
  /**
10
9
  * Yields a `WebhooksManager` instance scoped to the current app. Use when you
11
10
  * need to hold on to the manager outside an Effect (e.g. to call from inside
12
11
  * an async UI callback).
13
12
  */
14
- export declare const buildWebhooksManager: Effect.Effect<WebhooksManager<import("@instantdb/core").InstantUnknownSchemaDef>, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, AuthToken | CurrentApp>;
13
+ export declare const buildWebhooksManager: Effect.Effect<WebhooksManager<import("@instantdb/core").InstantUnknownSchemaDef>, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, import("../context/authToken.ts").AuthToken | CurrentApp>;
15
14
  /**
16
15
  * Fetches the app's schema and returns the sorted list of namespace names. Returns
17
16
  * `null` if the schema can't be fetched (network, auth, missing app, etc.) so
18
17
  * callers can fall back to a plain text prompt.
19
18
  */
20
- export declare const getRemoteNamespaces: Effect.Effect<string[] | null, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, AuthToken | CurrentApp>;
19
+ export declare const getRemoteNamespaces: Effect.Effect<string[] | null, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, import("../context/authToken.ts").AuthToken | CurrentApp>;
21
20
  /**
22
21
  * Pages through `manager.listEvents` until we have `limit` events or the server
23
22
  * runs out. Returns the events in their natural (newest-first) order.
24
23
  */
25
- export declare const fetchRecentEvents: (webhookId: string, limit: number) => Effect.Effect<WebhookEventInfo[], BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError | PlatformApiError, AuthToken | CurrentApp>;
24
+ export declare const fetchRecentEvents: (webhookId: string, limit: number) => Effect.Effect<WebhookEventInfo[], BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError | PlatformApiError, import("../context/authToken.ts").AuthToken | CurrentApp>;
26
25
  export declare const parseNamespaces: (raw: string | undefined) => Effect.Effect<string[] | undefined, BadArgsError, never>;
27
26
  export declare const parseActions: (raw: string | undefined) => Effect.Effect<WebhookAction[] | undefined, BadArgsError, never>;
28
27
  //# sourceMappingURL=webhooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAU5C,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAI1C,CAAC;AAEX,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAClC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAClD,eAAe,MAAM,mKAanB,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,8MAI/B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,2JAS9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,OAAO,MAAM,oLAc9D,CAAC;AAQL,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,GAAG,SAAS,6DAUnD,CAAC;AAEL,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,GAAG,SAAS,oEAkBhD,CAAC"}
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAI1C,CAAC;AAEX,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAClC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAClD,eAAe,MAAM,qMAanB,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gPAI/B,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,6LAS9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,OAAO,MAAM,sNAc9D,CAAC;AAQL,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,GAAG,SAAS,6DAUnD,CAAC;AAEL,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,GAAG,SAAS,oEAkBhD,CAAC"}
@@ -1,16 +1,9 @@
1
1
  import { Effect } from 'effect';
2
- import { PlatformApi as InstantPlatformApi, } from '@instantdb/platform';
3
- import { AuthToken } from "../context/authToken.js";
2
+ import {} from '@instantdb/platform';
4
3
  import { CurrentApp } from "../context/currentApp.js";
5
4
  import { PlatformApiError } from "../context/platformApi.js";
6
5
  import { BadArgsError } from "../errors.js";
7
- import { getBaseUrl } from "./http.js";
8
- const getAuthedPlatformApi = Effect.gen(function* () {
9
- const apiURI = yield* getBaseUrl;
10
- const authToken = yield* AuthToken;
11
- const token = yield* authToken.getAuthToken;
12
- return new InstantPlatformApi({ apiURI, auth: { token } });
13
- });
6
+ import { getAuthedPlatformApi } from "./platformApi.js";
14
7
  export const WEBHOOK_ACTIONS = [
15
8
  'create',
16
9
  'update',
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"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","sourcesContent":["import { Effect } from 'effect';\nimport {\n PlatformApi as InstantPlatformApi,\n type WebhookAction,\n type WebhookEventInfo,\n type WebhooksManager,\n} from '@instantdb/platform';\nimport { AuthToken } from '../context/authToken.ts';\nimport { CurrentApp } from '../context/currentApp.ts';\nimport { PlatformApiError } from '../context/platformApi.ts';\nimport { BadArgsError } from '../errors.ts';\nimport { getBaseUrl } from './http.ts';\n\nconst getAuthedPlatformApi = Effect.gen(function* () {\n const apiURI = yield* getBaseUrl;\n const authToken = yield* AuthToken;\n const token = yield* authToken.getAuthToken;\n return new InstantPlatformApi({ apiURI, auth: { token } });\n});\n\nexport const WEBHOOK_ACTIONS: readonly WebhookAction[] = [\n 'create',\n 'update',\n 'delete',\n] as const;\n\nexport const useWebhooksManager = <R>(\n fun: (manager: WebhooksManager<any>) => Promise<R>,\n errorMessage?: string,\n) =>\n Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n return yield* Effect.tryPromise({\n try: () => fun(api.webhooks(appId).manager),\n catch: (e) =>\n new PlatformApiError({\n message: errorMessage ?? 'Error using webhooks api',\n cause: e,\n }),\n });\n });\n\n/**\n * Yields a `WebhooksManager` instance scoped to the current app. Use when you\n * need to hold on to the manager outside an Effect (e.g. to call from inside\n * an async UI callback).\n */\nexport const buildWebhooksManager = Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n return api.webhooks(appId).manager;\n});\n\n/**\n * Fetches the app's schema and returns the sorted list of namespace names. Returns\n * `null` if the schema can't be fetched (network, auth, missing app, etc.) so\n * callers can fall back to a plain text prompt.\n */\nexport const getRemoteNamespaces = Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n const result = yield* Effect.tryPromise(() => api.getSchema(appId)).pipe(\n Effect.orElseSucceed(() => null),\n );\n if (!result) return null;\n const entities = result.schema?.entities ?? {};\n return Object.keys(entities).sort();\n});\n\n/**\n * Pages through `manager.listEvents` until we have `limit` events or the server\n * runs out. Returns the events in their natural (newest-first) order.\n */\nexport const fetchRecentEvents = (webhookId: string, limit: number) =>\n Effect.gen(function* () {\n const collected: WebhookEventInfo[] = [];\n let after: string | undefined;\n while (collected.length < limit) {\n const page = yield* useWebhooksManager(\n (m) => m.listEvents(webhookId, after ? { after } : undefined),\n 'Error listing webhook events',\n );\n collected.push(...page.events);\n if (!page.pageInfo.hasNextPage || !page.pageInfo.endCursor) break;\n after = page.pageInfo.endCursor;\n }\n return collected.slice(0, limit);\n });\n\nconst splitCsv = (s: string) =>\n s\n .split(',')\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n\nexport const parseNamespaces = (raw: string | undefined) =>\n Effect.gen(function* () {\n if (raw === undefined) return undefined;\n const namespaces = splitCsv(raw);\n if (namespaces.length === 0) {\n return yield* BadArgsError.make({\n message: '--namespaces must include at least one namespace',\n });\n }\n return namespaces;\n });\n\nexport const parseActions = (raw: string | undefined) =>\n Effect.gen(function* () {\n if (raw === undefined) return undefined;\n const tokens = splitCsv(raw);\n if (tokens.length === 0) {\n return yield* BadArgsError.make({\n message: '--actions must include at least one action',\n });\n }\n const invalid = tokens.filter(\n (t): t is string => !WEBHOOK_ACTIONS.includes(t as WebhookAction),\n );\n if (invalid.length > 0) {\n return yield* BadArgsError.make({\n message: `Invalid action${invalid.length === 1 ? '' : 's'}: ${invalid.join(', ')}. Must be one of: ${WEBHOOK_ACTIONS.join(', ')}`,\n });\n }\n return tokens as WebhookAction[];\n });\n"]}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAIN,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,CAAC,MAAM,eAAe,GAA6B;IACvD,QAAQ;IACR,QAAQ;IACR,QAAQ;CACA,CAAC;AAEX,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,GAAkD,EAClD,YAAqB,EACrB,EAAE,CACF,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IACpC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QAC9B,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;QAC3C,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CACX,IAAI,gBAAgB,CAAC;YACnB,OAAO,EAAE,YAAY,IAAI,0BAA0B;YACnD,KAAK,EAAE,CAAC;SACT,CAAC;KACL,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACtD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IACpC,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACrD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,oBAAoB,CAAC;IACxC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC;IACpC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CACtE,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CACjC,CAAC;IACF,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC;IAC/C,OAAO,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAAE,KAAa,EAAE,EAAE,CACpE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,SAAS,GAAuB,EAAE,CAAC;IACzC,IAAI,KAAyB,CAAC;IAC9B,OAAO,SAAS,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,kBAAkB,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,EAC7D,8BAA8B,CAC/B,CAAC;QACF,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS;YAAE,MAAM;QAClE,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;IAClC,CAAC;IACD,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEL,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,EAAE,CAC7B,CAAC;KACE,KAAK,CAAC,GAAG,CAAC;KACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAEjC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAuB,EAAE,EAAE,CACzD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;YAC9B,OAAO,EAAE,kDAAkD;SAC5D,CAAC,CAAC;IACL,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAuB,EAAE,EAAE,CACtD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;YAC9B,OAAO,EAAE,4CAA4C;SACtD,CAAC,CAAC;IACL,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAC3B,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAkB,CAAC,CAClE,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC;YAC9B,OAAO,EAAE,iBAAiB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;SAClI,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAyB,CAAC;AACnC,CAAC,CAAC,CAAC","sourcesContent":["import { Effect } from 'effect';\nimport {\n type WebhookAction,\n type WebhookEventInfo,\n type WebhooksManager,\n} from '@instantdb/platform';\nimport { CurrentApp } from '../context/currentApp.ts';\nimport { PlatformApiError } from '../context/platformApi.ts';\nimport { BadArgsError } from '../errors.ts';\nimport { getAuthedPlatformApi } from './platformApi.ts';\n\nexport const WEBHOOK_ACTIONS: readonly WebhookAction[] = [\n 'create',\n 'update',\n 'delete',\n] as const;\n\nexport const useWebhooksManager = <R>(\n fun: (manager: WebhooksManager<any>) => Promise<R>,\n errorMessage?: string,\n) =>\n Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n return yield* Effect.tryPromise({\n try: () => fun(api.webhooks(appId).manager),\n catch: (e) =>\n new PlatformApiError({\n message: errorMessage ?? 'Error using webhooks api',\n cause: e,\n }),\n });\n });\n\n/**\n * Yields a `WebhooksManager` instance scoped to the current app. Use when you\n * need to hold on to the manager outside an Effect (e.g. to call from inside\n * an async UI callback).\n */\nexport const buildWebhooksManager = Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n return api.webhooks(appId).manager;\n});\n\n/**\n * Fetches the app's schema and returns the sorted list of namespace names. Returns\n * `null` if the schema can't be fetched (network, auth, missing app, etc.) so\n * callers can fall back to a plain text prompt.\n */\nexport const getRemoteNamespaces = Effect.gen(function* () {\n const api = yield* getAuthedPlatformApi;\n const { appId } = yield* CurrentApp;\n const result = yield* Effect.tryPromise(() => api.getSchema(appId)).pipe(\n Effect.orElseSucceed(() => null),\n );\n if (!result) return null;\n const entities = result.schema?.entities ?? {};\n return Object.keys(entities).sort();\n});\n\n/**\n * Pages through `manager.listEvents` until we have `limit` events or the server\n * runs out. Returns the events in their natural (newest-first) order.\n */\nexport const fetchRecentEvents = (webhookId: string, limit: number) =>\n Effect.gen(function* () {\n const collected: WebhookEventInfo[] = [];\n let after: string | undefined;\n while (collected.length < limit) {\n const page = yield* useWebhooksManager(\n (m) => m.listEvents(webhookId, after ? { after } : undefined),\n 'Error listing webhook events',\n );\n collected.push(...page.events);\n if (!page.pageInfo.hasNextPage || !page.pageInfo.endCursor) break;\n after = page.pageInfo.endCursor;\n }\n return collected.slice(0, limit);\n });\n\nconst splitCsv = (s: string) =>\n s\n .split(',')\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n\nexport const parseNamespaces = (raw: string | undefined) =>\n Effect.gen(function* () {\n if (raw === undefined) return undefined;\n const namespaces = splitCsv(raw);\n if (namespaces.length === 0) {\n return yield* BadArgsError.make({\n message: '--namespaces must include at least one namespace',\n });\n }\n return namespaces;\n });\n\nexport const parseActions = (raw: string | undefined) =>\n Effect.gen(function* () {\n if (raw === undefined) return undefined;\n const tokens = splitCsv(raw);\n if (tokens.length === 0) {\n return yield* BadArgsError.make({\n message: '--actions must include at least one action',\n });\n }\n const invalid = tokens.filter(\n (t): t is string => !WEBHOOK_ACTIONS.includes(t as WebhookAction),\n );\n if (invalid.length > 0) {\n return yield* BadArgsError.make({\n message: `Invalid action${invalid.length === 1 ? '' : 's'}: ${invalid.join(', ')}. Must be one of: ${WEBHOOK_ACTIONS.join(', ')}`,\n });\n }\n return tokens as WebhookAction[];\n });\n"]}
package/dist/ui/lib.d.ts CHANGED
@@ -113,7 +113,7 @@ export declare class CancelledPromptError extends Error {
113
113
  * where cancelling may make more sense.
114
114
  */
115
115
  export declare function renderUnwrap<T>(view: Prompt<T>): Promise<T>;
116
- export declare function onTerminate(callback: (stdin: ReadStream, stdout: WriteStream) => void | undefined): void;
116
+ export declare function onTerminate(callback: ((stdin: ReadStream, stdout: WriteStream) => void) | undefined): void;
117
117
  export declare const prepareReadLine: () => {
118
118
  stdin: ReadStream;
119
119
  stdout: WriteStream;
@@ -1 +1 @@
1
- {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../../src/ui/lib.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../../src/ui/lib.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"lib.js","sourceRoot":"","sources":["../../src/ui/lib.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AACvC,OAAO,QAAQ,MAAM,eAAe,CAAC;AAErC,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAiB,EAAE,KAAc;IACzE,IAAI,CAAC,KAAK,IAAI,SAAS;QAAE,OAAO;IAChC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAWD,MAAM,OAAgB,MAAM;IAChB,QAAQ,CAAwB;IAClC,eAAe,GAAsC,EAAE,CAAC;IACxD,eAAe,GAAsC,EAAE,CAAC;IACxD,cAAc,GACpB,EAAE,CAAC;IAEE,QAAQ,GAA+B,SAAS,CAAC;IAExD,aAAa;QACX,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,QAAS,CAAC,aAAa,EAAE,CAAC;QACjC,CAAC;IACH,CAAC;IAED,YAAY,QAAyB;QACnC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAQD,EAAE,CAAC,IAAmC,EAAE,QAAa;QACnD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,CAAC;aAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,CAAC;aAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,MAAM,CAAC,QAAmB;QACxB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,QAAmB;QACxB,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,GAAuB,EAAE,GAAW;QACxC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACpD,CAAC;IAID,UAAU,CAAC,MAAwC;QACjD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,WAAW;IAEM;IADrB,WAAW,GAAG,CAAC,CAAC;IACvB,YAA4B,KAAU;QAAV,UAAK,GAAL,KAAK,CAAK;IAAG,CAAC;IAE1C,IAAI,CAAC,MAAmB;QACtB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC1C,IAAI,UAAU;gBAAE,MAAM,CAAC,aAAa,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,OAAO,CAAC,GAAuB,EAAE,GAAW;QAClD,IAAI,CAAC,GAAG;YAAE,OAAO,KAAK,CAAC;QAEvB,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACxB,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAC9D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;YACtB,IAAI,CAAC,WAAW;gBACd,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;YAClE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAM,EAAE;IAC9B,IAAI,OAA6C,CAAC;IAClD,IAAI,MAA+B,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC1C,OAAO,GAAG,GAAG,CAAC;QACd,MAAM,GAAG,GAAG,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO;QACP,MAAM;QACN,OAAO;KACR,CAAC;AACJ,CAAC,CAAC;AA2BF;;;;GAIG;AACH,IAAI,oBAAoB,GAAG,CAAC,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,oBAAoB,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,oBAAoB,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,oBAAoB,GAAG,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,OAAO,QAAQ;IAgBA;IACA;IACA;IACA;IAlBX,IAAI,GAAG,EAAE,CAAC;IACV,MAAM,GAAqC,MAAM,CAAC;IAClD,QAAQ,CAAgC;IACxC,OAAO,CAAwB;IAC/B,UAAU,CAAwB;IAElC,gBAAgB,GAAG,IAAI,CAAC;IAEzB,OAAO,CAAgC;IAEvC,mBAAmB,CAAC,KAAc;QACvC,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IAED,YACmB,IAAiB,EACjB,KAAiB,EACjB,MAAmB,EACnB,QAAkB;QAHlB,SAAI,GAAJ,IAAI,CAAa;QACjB,UAAK,GAAL,KAAK,CAAY;QACjB,WAAM,GAAN,MAAM,CAAa;QACnB,aAAQ,GAAR,QAAQ,CAAU;QAEnC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,yBAAyB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAElE,MAAM,QAAQ,GAAG,CAAC,GAAuB,EAAE,GAAW,EAAE,EAAE;YACxD,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC1C,IAAI,CAAC,aAAa,EAAE,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACvB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACxB,IAAI,gBAAgB,EAAE,CAAC;oBACrB,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC1C,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC1B,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC1B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;oBACxB,IAAI,CAAC,aAAa,EAAE,CAAC;oBACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACvB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACxB,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;oBACtD,OAAO;gBACT,CAAC;gBAED,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC1B,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;oBAC1B,IAAI,CAAC,aAAa,EAAE,CAAC;oBACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACvB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACxB,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;oBACjE,OAAO;gBACT,CAAC;YACH,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACvB,CAAC,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEvB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAgB,CAAC;QACtD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QAExB,IAAI,CAAC,OAAO,GAAG,CAAC,KAAmB,EAAE,EAAE;YACrC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;YAC1B,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC,CAAC;QAEF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,CAAC,GAAW,EAAE,EAAE;YACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,QAAQ,CAAC,QAAkC;QACjD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,yBAAyB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACnE,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,0EAA0E;QAC1E,QAAQ;QACR,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;YACtC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,8BAA8B;YAC3D,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;gBACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;oBAC5B,IAAI,CAAC,GAAG,CAAC;wBAAE,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;gBAChD,CAAC;YACH,CAAC;YACD,oBAAoB,IAAI,IAAI,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,YAAY,CAAC,KAAsB;QACjC,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,aAAa;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,UAAU,GAAG,MAAM,CAAC;QACxB,wEAAwE;QACxE,0EAA0E;QAC1E,sDAAsD;QACtD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxD,UAAU,IAAI,IAAI,CAAC;QACrB,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC;QACzE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QAEvB,IAAI,CAAC,UAAU,CAAC,GAAG,WAAW,GAAG,UAAU,EAAE,CAAC,CAAC;IACjD,CAAC;CACF;AAID,MAAM,UAAU,MAAM,CAAC,IAAS;IAC9B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE,CAAC;IACtD,IAAI,IAAI,YAAY,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC7D,QAAQ,CAAC,aAAa,EAAE,CAAC;QACzB,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjB,OAAO;AACT,CAAC;AAED,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,IAAe;IACnD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC7D,QAAQ,CAAC,aAAa,EAAE,CAAC;IACzB,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAgB,CAAC;IACxD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,qEAAqE;QACrE,yEAAyE;QACzE,IAAI,MAAM,CAAC,IAAI,YAAY,KAAK,EAAE,CAAC;YACjC,MAAM,MAAM,CAAC,IAAI,CAAC;QACpB,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;AACH,CAAC;AAED,IAAI,gBAES,CAAC;AAEd,MAAM,UAAU,WAAW,CACzB,QAAsE;IAEtE,gBAAgB,GAAG,QAAQ,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,GAI7B,EAAE;IACF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE9B,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,KAAK;QACZ,iBAAiB,EAAE,EAAE;KACtB,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEvC,OAAO;QACL,KAAK;QACL,MAAM;QACN,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,KAAK,GAAG,CAAC,GAAW,EAAE,EAAE;IAC5B,MAAM,OAAO,GAAG;QACd,8HAA8H;QAC9H,wDAAwD;KACzD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACrC,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC9D,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAE5D,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,MAAc,EAAE,OAAe;IAC5D,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAE/C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpC,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC,CAAC","sourcesContent":["import { ReadStream, WriteStream } from 'node:tty';\nimport { cursor, erase } from 'sisteransi';\nimport throttle from 'lodash.throttle';\nimport readline from 'node:readline';\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Set terminal raw mode on stdin, with a Windows workaround.\n *\n * Raw mode (true):\n * - Input available character-by-character (not line-buffered)\n * - No echo of typed characters\n * - Ctrl+C doesn't send SIGINT (must handle manually)\n * - Required to capture arrow keys and other special keys\n *\n * Normal mode (false):\n * - Input is line-buffered (available after Enter)\n * - Typed characters are echoed\n * - Ctrl+C sends SIGINT as normal\n *\n * Windows workaround: We skip disabling raw mode on Windows because\n * toggling it between prompts causes a race condition that breaks\n * subsequent keypress events. Raw mode is automatically reset when\n * the process exits, so this is safe.\n *\n * See: https://github.com/bombshell-dev/clack/issues/176\n */\nexport function setRawModeWindowsFriendly(input: ReadStream, value: boolean) {\n if (!value && isWindows) return;\n input.setRawMode(value);\n}\n\nexport interface Closable {\n close(): void;\n}\n\nexport type ModifyOutputFn = (\n output: string,\n status?: 'idle' | 'submitted' | 'aborted',\n) => string;\n\nexport abstract class Prompt<RESULT> {\n protected terminal: ITerminal | undefined;\n private attachCallbacks: ((terminal: ITerminal) => void)[] = [];\n private detachCallbacks: ((terminal: ITerminal) => void)[] = [];\n private inputCallbacks: ((str: string | undefined, key: AnyKey) => void)[] =\n [];\n\n public modifier: ModifyOutputFn | undefined = undefined;\n\n requestLayout() {\n if (this.terminal) {\n this.terminal!.requestLayout();\n }\n }\n\n constructor(modifier?: ModifyOutputFn) {\n this.modifier = modifier;\n }\n\n on(type: 'attach', callback: (terminal: ITerminal) => void): void;\n on(type: 'detach', callback: (terminal: ITerminal) => void): void;\n on(\n type: 'input',\n callback: (str: string | undefined, key: AnyKey) => void,\n ): void;\n on(type: 'attach' | 'detach' | 'input', callback: any): void {\n if (type === 'attach') {\n this.attachCallbacks.push(callback);\n } else if (type === 'detach') {\n this.detachCallbacks.push(callback);\n } else if (type === 'input') {\n this.inputCallbacks.push(callback);\n }\n }\n\n attach(terminal: ITerminal) {\n this.terminal = terminal;\n this.attachCallbacks.forEach((it) => it(terminal));\n }\n\n detach(terminal: ITerminal) {\n this.detachCallbacks.forEach((it) => it(terminal));\n this.terminal = undefined;\n }\n\n input(str: string | undefined, key: AnyKey) {\n this.inputCallbacks.forEach((it) => it(str, key));\n }\n\n abstract result(): RESULT;\n abstract render(status: 'idle' | 'submitted' | 'aborted'): string;\n fullRender(status: 'idle' | 'submitted' | 'aborted'): string {\n if (this.modifier) {\n return this.modifier(this.render(status), status);\n }\n return this.render(status);\n }\n}\n\nexport class SelectState<T> {\n public selectedIdx = 0;\n constructor(public readonly items: T[]) {}\n\n bind(prompt: Prompt<any>) {\n prompt.on('input', (str, key) => {\n const invalidate = this.consume(str, key);\n if (invalidate) prompt.requestLayout();\n });\n }\n\n private consume(str: string | undefined, key: AnyKey): boolean {\n if (!key) return false;\n\n if (key.name === 'down') {\n this.selectedIdx = (this.selectedIdx + 1) % this.items.length;\n return true;\n }\n\n if (key.name === 'up') {\n this.selectedIdx -= 1;\n this.selectedIdx =\n this.selectedIdx < 0 ? this.items.length - 1 : this.selectedIdx;\n return true;\n }\n\n return false;\n }\n}\n\nexport const deferred = <T>() => {\n let resolve!: (value: T | PromiseLike<T>) => void;\n let reject!: (reason?: any) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n return {\n resolve,\n reject,\n promise,\n };\n};\n\nexport interface ITerminal {\n toggleCursor(state: 'hide' | 'show'): void;\n requestLayout(): void;\n resolve(value: Prompted<{}>): void;\n setAllowInteraction(value: boolean): void;\n}\n\nexport type AnyKey = {\n sequence: string;\n name: string | undefined;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n};\n\ntype Prompted<T> =\n | {\n data: undefined;\n status: 'aborted';\n }\n | {\n data: T;\n status: 'submitted';\n };\n\n/**\n * Module-level counter that tracks the cumulative line count of submitted\n * prompts. A command opts in to \"erase the trail at the very end\" by calling\n * {@link clearPromptTrail} right before printing its final summary.\n */\nlet promptTrailLineCount = 0;\n\n/**\n * Walk the cursor up by however many lines submitted prompts have written, and\n * erase from there to the end of the screen. Resets the counter. No-op on a\n * non-TTY stdout (e.g. when output is piped). Vanished prompts don't\n * contribute, so calling this only erases the dimmed trail.\n */\nexport function clearPromptTrail(): void {\n if (process.stdout.isTTY && promptTrailLineCount > 0) {\n process.stdout.write(cursor.up(promptTrailLineCount) + erase.down());\n }\n promptTrailLineCount = 0;\n}\n\nexport class Terminal implements ITerminal {\n private text = '';\n private status: 'idle' | 'submitted' | 'aborted' = 'idle';\n private _resolve: (value: Prompted<{}>) => void;\n private promise: Promise<Prompted<{}>>;\n private renderFunc: (str: string) => void;\n\n private allowInteraction = true;\n\n public resolve: (value: Prompted<{}>) => void;\n\n public setAllowInteraction(value: boolean) {\n this.allowInteraction = value;\n }\n\n constructor(\n private readonly view: Prompt<any>,\n private readonly stdin: ReadStream,\n private readonly stdout: WriteStream,\n private readonly closable: Closable,\n ) {\n if (this.stdin.isTTY) setRawModeWindowsFriendly(this.stdin, true);\n\n const keypress = (str: string | undefined, key: AnyKey) => {\n if (key.name === 'c' && key.ctrl === true) {\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n if (terminateHandler) {\n terminateHandler(this.stdin, this.stdout);\n return;\n }\n this.stdout.write(`\\n^C\\n`);\n process.exit(1);\n }\n\n if (this.allowInteraction) {\n if (key.name === 'escape') {\n this.status = 'aborted';\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n this._resolve({ status: 'aborted', data: undefined });\n return;\n }\n\n if (key.name === 'return') {\n this.status = 'submitted';\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n this._resolve({ status: 'submitted', data: this.view.result() });\n return;\n }\n }\n\n view.input(str, key);\n };\n\n this.stdin.on('keypress', keypress);\n this.view.attach(this);\n\n const { resolve, promise } = deferred<Prompted<{}>>();\n this._resolve = resolve;\n\n this.resolve = (value: Prompted<{}>) => {\n this.status = 'submitted';\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n this._resolve(value);\n };\n\n this.promise = promise;\n\n this.renderFunc = throttle((str: string) => {\n this.stdout.write(str);\n });\n }\n\n private tearDown(keypress: (...args: any[]) => void) {\n this.stdout.write(cursor.show);\n this.stdin.removeListener('keypress', keypress);\n if (this.stdin.isTTY) setRawModeWindowsFriendly(this.stdin, false);\n this.closable.close();\n // Track rows the cursor advanced past so a command can erase the whole\n // prompt trail at the end. Counts each \\n plus wraps for lines wider than\n // the terminal — mirrors `clear()`'s formula so wrapped output is still\n // fully cleared. Skip vanished output (whitespace-only after the modifier\n // ran).\n if (this.status === 'submitted' && this.text.trim().length > 0) {\n const cols = this.stdout.columns || 0;\n const lines = this.text.split(/\\r?\\n/);\n let rows = lines.length - 1; // one cursor-down per newline\n if (cols > 0) {\n for (const line of lines) {\n const w = stringWidth(line);\n if (w > 0) rows += Math.floor((w - 1) / cols);\n }\n }\n promptTrailLineCount += rows;\n }\n }\n\n result(): Promise<{}> {\n return this.promise;\n }\n\n toggleCursor(state: 'hide' | 'show') {\n if (state === 'hide') {\n this.stdout.write(cursor.hide);\n } else {\n this.stdout.write(cursor.show);\n }\n }\n\n requestLayout() {\n const string = this.view.fullRender(this.status);\n let realString = string;\n // Only ensure a trailing newline when there's content. Vanished renders\n // (empty string after modifyOutput) would otherwise inject a phantom line\n // that pushes the next prompt down on each iteration.\n if (realString.length > 0 && !realString.endsWith('\\n')) {\n realString += '\\n';\n }\n const realText = this.text.endsWith('\\n') ? this.text : `${this.text}\\n`;\n const clearPrefix = this.text ? clear(realText, this.stdout.columns) : '';\n this.text = realString;\n\n this.renderFunc(`${clearPrefix}${realString}`);\n }\n}\n\nexport function render<T>(view: Prompt<T>): Promise<Prompted<T>>;\nexport function render(view: string): void;\nexport function render(view: any): any {\n const { stdin, stdout, closable } = prepareReadLine();\n if (view instanceof Prompt) {\n const terminal = new Terminal(view, stdin, stdout, closable);\n terminal.requestLayout();\n return terminal.result();\n }\n\n stdout.write(`${view}\\n`);\n closable.close();\n return;\n}\n\nexport class CancelledPromptError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = 'CancelledPromptError';\n }\n}\n\n/**\n * Renders a prompt object and throws if the Prompt was \"cancelled\"\n * If using the standard render function you must check if the result ended in a cancellation before accessing the data.\n * Cancellations are rare so this is more of a future proof for future components\n * where cancelling may make more sense.\n */\nexport async function renderUnwrap<T>(view: Prompt<T>): Promise<T> {\n const { stdin, stdout, closable } = prepareReadLine();\n const terminal = new Terminal(view, stdin, stdout, closable);\n terminal.requestLayout();\n const result = (await terminal.result()) as Prompted<T>;\n if (result.status === 'aborted') {\n throw new CancelledPromptError('Prompt was aborted');\n } else {\n // Prompt.result may throw an error but it is swallowed by the use of\n // Terminal. Terminal.result() just returns the prompt's internal promise\n if (result.data instanceof Error) {\n throw result.data;\n }\n return result.data;\n }\n}\n\nlet terminateHandler:\n | ((stdin: ReadStream, stdout: WriteStream) => void)\n | undefined;\n\nexport function onTerminate(\n callback: (stdin: ReadStream, stdout: WriteStream) => void | undefined,\n) {\n terminateHandler = callback;\n}\n\nexport const prepareReadLine = (): {\n stdin: ReadStream;\n stdout: WriteStream;\n closable: Closable;\n} => {\n const stdin = process.stdin;\n const stdout = process.stdout;\n\n const rl = readline.createInterface({\n input: stdin,\n escapeCodeTimeout: 50,\n });\n\n readline.emitKeypressEvents(stdin, rl);\n\n return {\n stdin,\n stdout,\n closable: rl,\n };\n};\n\nconst strip = (str: string) => {\n const pattern = [\n '[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)',\n '(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PRZcf-ntqry=><~]))',\n ].join('|');\n\n const RGX = new RegExp(pattern, 'g');\n return typeof str === 'string' ? str.replace(RGX, '') : str;\n};\n\nconst stringWidth = (str: string) => [...strip(str)].length;\n\nexport const clear = function (prompt: string, perLine: number) {\n if (!perLine) return erase.line + cursor.to(0);\n\n let rows = 0;\n const lines = prompt.split(/\\r?\\n/);\n for (let line of lines) {\n rows += 1 + Math.floor(Math.max(stringWidth(line) - 1, 0) / perLine);\n }\n\n return erase.lines(rows);\n};\n"]}
1
+ {"version":3,"file":"lib.js","sourceRoot":"","sources":["../../src/ui/lib.ts"],"names":[],"mappings":"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","sourcesContent":["import { ReadStream, WriteStream } from 'node:tty';\nimport { cursor, erase } from 'sisteransi';\nimport throttle from 'lodash.throttle';\nimport readline from 'node:readline';\n\nconst isWindows = process.platform === 'win32';\n\n/**\n * Set terminal raw mode on stdin, with a Windows workaround.\n *\n * Raw mode (true):\n * - Input available character-by-character (not line-buffered)\n * - No echo of typed characters\n * - Ctrl+C doesn't send SIGINT (must handle manually)\n * - Required to capture arrow keys and other special keys\n *\n * Normal mode (false):\n * - Input is line-buffered (available after Enter)\n * - Typed characters are echoed\n * - Ctrl+C sends SIGINT as normal\n *\n * Windows workaround: We skip disabling raw mode on Windows because\n * toggling it between prompts causes a race condition that breaks\n * subsequent keypress events. Raw mode is automatically reset when\n * the process exits, so this is safe.\n *\n * See: https://github.com/bombshell-dev/clack/issues/176\n */\nexport function setRawModeWindowsFriendly(input: ReadStream, value: boolean) {\n if (!value && isWindows) return;\n input.setRawMode(value);\n}\n\nexport interface Closable {\n close(): void;\n}\n\nexport type ModifyOutputFn = (\n output: string,\n status?: 'idle' | 'submitted' | 'aborted',\n) => string;\n\nexport abstract class Prompt<RESULT> {\n protected terminal: ITerminal | undefined;\n private attachCallbacks: ((terminal: ITerminal) => void)[] = [];\n private detachCallbacks: ((terminal: ITerminal) => void)[] = [];\n private inputCallbacks: ((str: string | undefined, key: AnyKey) => void)[] =\n [];\n\n public modifier: ModifyOutputFn | undefined = undefined;\n\n requestLayout() {\n if (this.terminal) {\n this.terminal!.requestLayout();\n }\n }\n\n constructor(modifier?: ModifyOutputFn) {\n this.modifier = modifier;\n }\n\n on(type: 'attach', callback: (terminal: ITerminal) => void): void;\n on(type: 'detach', callback: (terminal: ITerminal) => void): void;\n on(\n type: 'input',\n callback: (str: string | undefined, key: AnyKey) => void,\n ): void;\n on(type: 'attach' | 'detach' | 'input', callback: any): void {\n if (type === 'attach') {\n this.attachCallbacks.push(callback);\n } else if (type === 'detach') {\n this.detachCallbacks.push(callback);\n } else if (type === 'input') {\n this.inputCallbacks.push(callback);\n }\n }\n\n attach(terminal: ITerminal) {\n this.terminal = terminal;\n this.attachCallbacks.forEach((it) => it(terminal));\n }\n\n detach(terminal: ITerminal) {\n this.detachCallbacks.forEach((it) => it(terminal));\n this.terminal = undefined;\n }\n\n input(str: string | undefined, key: AnyKey) {\n this.inputCallbacks.forEach((it) => it(str, key));\n }\n\n abstract result(): RESULT;\n abstract render(status: 'idle' | 'submitted' | 'aborted'): string;\n fullRender(status: 'idle' | 'submitted' | 'aborted'): string {\n if (this.modifier) {\n return this.modifier(this.render(status), status);\n }\n return this.render(status);\n }\n}\n\nexport class SelectState<T> {\n public selectedIdx = 0;\n constructor(public readonly items: T[]) {}\n\n bind(prompt: Prompt<any>) {\n prompt.on('input', (str, key) => {\n const invalidate = this.consume(str, key);\n if (invalidate) prompt.requestLayout();\n });\n }\n\n private consume(str: string | undefined, key: AnyKey): boolean {\n if (!key) return false;\n\n if (key.name === 'down') {\n this.selectedIdx = (this.selectedIdx + 1) % this.items.length;\n return true;\n }\n\n if (key.name === 'up') {\n this.selectedIdx -= 1;\n this.selectedIdx =\n this.selectedIdx < 0 ? this.items.length - 1 : this.selectedIdx;\n return true;\n }\n\n return false;\n }\n}\n\nexport const deferred = <T>() => {\n let resolve!: (value: T | PromiseLike<T>) => void;\n let reject!: (reason?: any) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n return {\n resolve,\n reject,\n promise,\n };\n};\n\nexport interface ITerminal {\n toggleCursor(state: 'hide' | 'show'): void;\n requestLayout(): void;\n resolve(value: Prompted<{}>): void;\n setAllowInteraction(value: boolean): void;\n}\n\nexport type AnyKey = {\n sequence: string;\n name: string | undefined;\n ctrl: boolean;\n meta: boolean;\n shift: boolean;\n};\n\ntype Prompted<T> =\n | {\n data: undefined;\n status: 'aborted';\n }\n | {\n data: T;\n status: 'submitted';\n };\n\n/**\n * Module-level counter that tracks the cumulative line count of submitted\n * prompts. A command opts in to \"erase the trail at the very end\" by calling\n * {@link clearPromptTrail} right before printing its final summary.\n */\nlet promptTrailLineCount = 0;\n\n/**\n * Walk the cursor up by however many lines submitted prompts have written, and\n * erase from there to the end of the screen. Resets the counter. No-op on a\n * non-TTY stdout (e.g. when output is piped). Vanished prompts don't\n * contribute, so calling this only erases the dimmed trail.\n */\nexport function clearPromptTrail(): void {\n if (process.stdout.isTTY && promptTrailLineCount > 0) {\n process.stdout.write(cursor.up(promptTrailLineCount) + erase.down());\n }\n promptTrailLineCount = 0;\n}\n\nexport class Terminal implements ITerminal {\n private text = '';\n private status: 'idle' | 'submitted' | 'aborted' = 'idle';\n private _resolve: (value: Prompted<{}>) => void;\n private promise: Promise<Prompted<{}>>;\n private renderFunc: (str: string) => void;\n\n private allowInteraction = true;\n\n public resolve: (value: Prompted<{}>) => void;\n\n public setAllowInteraction(value: boolean) {\n this.allowInteraction = value;\n }\n\n constructor(\n private readonly view: Prompt<any>,\n private readonly stdin: ReadStream,\n private readonly stdout: WriteStream,\n private readonly closable: Closable,\n ) {\n if (this.stdin.isTTY) setRawModeWindowsFriendly(this.stdin, true);\n\n const keypress = (str: string | undefined, key: AnyKey) => {\n if (key.name === 'c' && key.ctrl === true) {\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n if (terminateHandler) {\n terminateHandler(this.stdin, this.stdout);\n return;\n }\n this.stdout.write(`\\n^C\\n`);\n process.exit(1);\n }\n\n if (this.allowInteraction) {\n if (key.name === 'escape') {\n this.status = 'aborted';\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n this._resolve({ status: 'aborted', data: undefined });\n return;\n }\n\n if (key.name === 'return') {\n this.status = 'submitted';\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n this._resolve({ status: 'submitted', data: this.view.result() });\n return;\n }\n }\n\n view.input(str, key);\n };\n\n this.stdin.on('keypress', keypress);\n this.view.attach(this);\n\n const { resolve, promise } = deferred<Prompted<{}>>();\n this._resolve = resolve;\n\n this.resolve = (value: Prompted<{}>) => {\n this.status = 'submitted';\n this.requestLayout();\n this.view.detach(this);\n this.tearDown(keypress);\n this._resolve(value);\n };\n\n this.promise = promise;\n\n this.renderFunc = throttle((str: string) => {\n this.stdout.write(str);\n });\n }\n\n private tearDown(keypress: (...args: any[]) => void) {\n this.stdout.write(cursor.show);\n this.stdin.removeListener('keypress', keypress);\n if (this.stdin.isTTY) setRawModeWindowsFriendly(this.stdin, false);\n this.closable.close();\n // Track rows the cursor advanced past so a command can erase the whole\n // prompt trail at the end. Counts each \\n plus wraps for lines wider than\n // the terminal — mirrors `clear()`'s formula so wrapped output is still\n // fully cleared. Skip vanished output (whitespace-only after the modifier\n // ran).\n if (this.status === 'submitted' && this.text.trim().length > 0) {\n const cols = this.stdout.columns || 0;\n const lines = this.text.split(/\\r?\\n/);\n let rows = lines.length - 1; // one cursor-down per newline\n if (cols > 0) {\n for (const line of lines) {\n const w = stringWidth(line);\n if (w > 0) rows += Math.floor((w - 1) / cols);\n }\n }\n promptTrailLineCount += rows;\n }\n }\n\n result(): Promise<{}> {\n return this.promise;\n }\n\n toggleCursor(state: 'hide' | 'show') {\n if (state === 'hide') {\n this.stdout.write(cursor.hide);\n } else {\n this.stdout.write(cursor.show);\n }\n }\n\n requestLayout() {\n const string = this.view.fullRender(this.status);\n let realString = string;\n // Only ensure a trailing newline when there's content. Vanished renders\n // (empty string after modifyOutput) would otherwise inject a phantom line\n // that pushes the next prompt down on each iteration.\n if (realString.length > 0 && !realString.endsWith('\\n')) {\n realString += '\\n';\n }\n const realText = this.text.endsWith('\\n') ? this.text : `${this.text}\\n`;\n const clearPrefix = this.text ? clear(realText, this.stdout.columns) : '';\n this.text = realString;\n\n this.renderFunc(`${clearPrefix}${realString}`);\n }\n}\n\nexport function render<T>(view: Prompt<T>): Promise<Prompted<T>>;\nexport function render(view: string): void;\nexport function render(view: any): any {\n const { stdin, stdout, closable } = prepareReadLine();\n if (view instanceof Prompt) {\n const terminal = new Terminal(view, stdin, stdout, closable);\n terminal.requestLayout();\n return terminal.result();\n }\n\n stdout.write(`${view}\\n`);\n closable.close();\n return;\n}\n\nexport class CancelledPromptError extends Error {\n constructor(message?: string) {\n super(message);\n this.name = 'CancelledPromptError';\n }\n}\n\n/**\n * Renders a prompt object and throws if the Prompt was \"cancelled\"\n * If using the standard render function you must check if the result ended in a cancellation before accessing the data.\n * Cancellations are rare so this is more of a future proof for future components\n * where cancelling may make more sense.\n */\nexport async function renderUnwrap<T>(view: Prompt<T>): Promise<T> {\n const { stdin, stdout, closable } = prepareReadLine();\n const terminal = new Terminal(view, stdin, stdout, closable);\n terminal.requestLayout();\n const result = (await terminal.result()) as Prompted<T>;\n if (result.status === 'aborted') {\n throw new CancelledPromptError('Prompt was aborted');\n } else {\n // Prompt.result may throw an error but it is swallowed by the use of\n // Terminal. Terminal.result() just returns the prompt's internal promise\n if (result.data instanceof Error) {\n throw result.data;\n }\n return result.data;\n }\n}\n\nlet terminateHandler:\n | ((stdin: ReadStream, stdout: WriteStream) => void)\n | undefined;\n\nexport function onTerminate(\n callback: ((stdin: ReadStream, stdout: WriteStream) => void) | undefined,\n) {\n terminateHandler = callback;\n}\n\nexport const prepareReadLine = (): {\n stdin: ReadStream;\n stdout: WriteStream;\n closable: Closable;\n} => {\n const stdin = process.stdin;\n const stdout = process.stdout;\n\n const rl = readline.createInterface({\n input: stdin,\n escapeCodeTimeout: 50,\n });\n\n readline.emitKeypressEvents(stdin, rl);\n\n return {\n stdin,\n stdout,\n closable: rl,\n };\n};\n\nconst strip = (str: string) => {\n const pattern = [\n '[\\\\u001B\\\\u009B][[\\\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]+)*|[a-zA-Z\\\\d]+(?:;[-a-zA-Z\\\\d\\\\/#&.:=?%@~_]*)*)?\\\\u0007)',\n '(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PRZcf-ntqry=><~]))',\n ].join('|');\n\n const RGX = new RegExp(pattern, 'g');\n return typeof str === 'string' ? str.replace(RGX, '') : str;\n};\n\nconst stringWidth = (str: string) => [...strip(str)].length;\n\nexport const clear = function (prompt: string, perLine: number) {\n if (!perLine) return erase.line + cursor.to(0);\n\n let rows = 0;\n const lines = prompt.split(/\\r?\\n/);\n for (let line of lines) {\n rows += 1 + Math.floor(Math.max(stringWidth(line) - 1, 0) / perLine);\n }\n\n return erase.lines(rows);\n};\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "instant-cli",
3
3
  "type": "module",
4
- "version": "1.0.60",
4
+ "version": "1.0.61",
5
5
  "description": "Instant's CLI",
6
6
  "license": "Apache-2.0",
7
7
  "homepage": "https://github.com/instantdb/instant/tree/main/client/packages/cli",
@@ -31,6 +31,7 @@
31
31
  "@commander-js/extra-typings": "^14.0.0",
32
32
  "@effect/platform": "^0.94.1",
33
33
  "@effect/platform-node": "^0.104.0",
34
+ "@zip.js/zip.js": "^2.8.34",
34
35
  "acorn": "^8.15.0",
35
36
  "acorn-typescript": "^1.4.13",
36
37
  "ansi-escapes": "4.3.2",
@@ -56,9 +57,9 @@
56
57
  "strip-ansi": "^7.1.2",
57
58
  "supports-hyperlinks": "^4.4.0",
58
59
  "unconfig": "^7.5.0",
59
- "@instantdb/core": "1.0.60",
60
- "@instantdb/platform": "1.0.60",
61
- "@instantdb/version": "1.0.60"
60
+ "@instantdb/core": "1.0.61",
61
+ "@instantdb/platform": "1.0.61",
62
+ "@instantdb/version": "1.0.61"
62
63
  },
63
64
  "devDependencies": {
64
65
  "@babel/core": "^7.17.9",
@@ -0,0 +1,231 @@
1
+ import { existsSync, statSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { Effect } from 'effect';
5
+ import {
6
+ backupZipName,
7
+ estimateZipSize,
8
+ formatFileSize,
9
+ type AppBackup,
10
+ type BackupsManager,
11
+ } from '@instantdb/platform';
12
+ import type { backupDownloadDef, OptsFromCommand } from '../../index.ts';
13
+ import { BadArgsError } from '../../errors.ts';
14
+ import { GlobalOpts } from '../../context/globalOpts.ts';
15
+ import { PlatformApiError } from '../../context/platformApi.ts';
16
+ import { buildBackupsManager, useBackupsManager } from '../../lib/backups.ts';
17
+ import {
18
+ downloadBackupToFile,
19
+ type BackupDownloadProgress,
20
+ type BackupDownloadResult,
21
+ } from '../../lib/backupDownload.ts';
22
+ import { promptOk, runUIEffect } from '../../lib/ui.ts';
23
+ import { onTerminate, renderUnwrap } from '../../ui/lib.ts';
24
+ import { UI } from '../../ui/index.ts';
25
+ import { relativeTime, renderBackupsTable, stripControlChars } from './list.ts';
26
+
27
+ const pickBackup = (
28
+ backups: AppBackup[],
29
+ backupId: string | undefined,
30
+ opts: { latest?: boolean },
31
+ ) =>
32
+ Effect.gen(function* () {
33
+ if (backupId && opts.latest) {
34
+ return yield* BadArgsError.make({
35
+ message: 'Pass either a backup id or --latest, not both.',
36
+ });
37
+ }
38
+ if (backupId) {
39
+ const found = backups.find((b) => b.id === backupId);
40
+ if (!found) {
41
+ return yield* BadArgsError.make({
42
+ message: `No backup found with id ${backupId}.`,
43
+ });
44
+ }
45
+ return found;
46
+ }
47
+
48
+ // The server returns newest first; sort anyway so --latest can't silently
49
+ // pick the wrong one.
50
+ const sorted = [...backups].sort(
51
+ (a, b) => b.backupAt.getTime() - a.backupAt.getTime(),
52
+ );
53
+ if (opts.latest) {
54
+ return sorted[0];
55
+ }
56
+
57
+ const { yes } = yield* GlobalOpts;
58
+ if (yes) {
59
+ return yield* BadArgsError.make({
60
+ message: 'Must specify a backup id or --latest',
61
+ });
62
+ }
63
+
64
+ // The picker stays lean: id, age, and description are what you choose
65
+ // by, in the table's column order. Sizes and expiry show up in the
66
+ // confirm table right after, where headers explain them.
67
+ const cells = sorted.map((backup) => [
68
+ backup.id,
69
+ `created ${relativeTime(backup.backupAt)}`,
70
+ backup.description ? stripControlChars(backup.description) : '',
71
+ ]);
72
+ const widths = cells[0].map((_, i) =>
73
+ Math.max(...cells.map((row) => row[i].length)),
74
+ );
75
+ return yield* runUIEffect(
76
+ new UI.Select({
77
+ options: sorted.map((backup, idx) => ({
78
+ label: cells[idx].map((cell, i) => cell.padEnd(widths[i])).join(' '),
79
+ value: backup,
80
+ })),
81
+ promptText: 'Select a backup to download:',
82
+ }),
83
+ );
84
+ });
85
+
86
+ // One compact line for the spinner as the pipeline ticks.
87
+ function progressLine(p: BackupDownloadProgress): string {
88
+ const parts: string[] = [];
89
+ parts.push(
90
+ p.entitiesTotal == null
91
+ ? 'listing namespaces…'
92
+ : `namespaces ${p.entitiesCompleted}/${p.entitiesTotal}`,
93
+ );
94
+ if (p.filesTotal !== 0) {
95
+ parts.push(
96
+ p.filesTotal == null
97
+ ? 'listing storage files…'
98
+ : `storage files ${p.filesCompleted}/${p.filesTotal}`,
99
+ );
100
+ }
101
+ let bytes = formatFileSize(p.zipBytes);
102
+ if (p.bytesTotal != null && p.bytesTotal > 0) {
103
+ const pct = Math.min(100, Math.round((p.bytesRead / p.bytesTotal) * 100));
104
+ bytes += ` (${pct}%)`;
105
+ }
106
+ parts.push(bytes);
107
+ const currentEntry = p.currentEntity || p.currentFile;
108
+ if (currentEntry) {
109
+ parts.push(currentEntry);
110
+ }
111
+ let line = parts.join(' · ');
112
+ // The spinner prefixes a frame glyph; truncate so the line can't wrap.
113
+ const width = (process.stdout.columns || 80) - 4;
114
+ if (line.length > width) {
115
+ line = line.slice(0, Math.max(0, width - 1)) + '…';
116
+ }
117
+ return line;
118
+ }
119
+
120
+ // Returns null when the download was cancelled. While the spinner is
121
+ // attached the terminal is raw, so ctrl-c arrives through the UI's
122
+ // terminate hook rather than SIGINT; both routes abort the same controller
123
+ // and the pipeline removes its partial file before we return. Outside the
124
+ // spinner (non-TTY runs), SIGINT covers it.
125
+ async function runDownload(
126
+ manager: BackupsManager,
127
+ backup: AppBackup,
128
+ outPath: string,
129
+ ): Promise<BackupDownloadResult | null> {
130
+ const controller = new AbortController();
131
+ const onSigint = () => controller.abort();
132
+ process.once('SIGINT', onSigint);
133
+ onTerminate(() => controller.abort());
134
+ try {
135
+ let spinner: UI.Spinner<unknown> | null = null;
136
+ // Settled into a sentinel so the spinner always disappears cleanly and
137
+ // cancellation/error output stays with the command below.
138
+ const settled = downloadBackupToFile({
139
+ manager,
140
+ backup,
141
+ outPath,
142
+ signal: controller.signal,
143
+ onProgress: (p) => spinner?.updateText(progressLine(p)),
144
+ }).then(
145
+ (result) => ({ result, error: null as unknown }),
146
+ (error: unknown) => ({ result: null, error }),
147
+ );
148
+ if (process.stdout.isTTY) {
149
+ spinner = new UI.Spinner({
150
+ promise: settled,
151
+ workingText: 'Preparing download…',
152
+ disappearWhenDone: true,
153
+ });
154
+ await renderUnwrap(spinner);
155
+ }
156
+ const { result, error } = await settled;
157
+ if (error) {
158
+ if ((error as { name?: string })?.name === 'AbortError') return null;
159
+ throw error;
160
+ }
161
+ return result;
162
+ } finally {
163
+ process.removeListener('SIGINT', onSigint);
164
+ onTerminate(undefined);
165
+ }
166
+ }
167
+
168
+ export const backupDownloadCmd = Effect.fn(function* (
169
+ backupId: string | undefined,
170
+ opts: OptsFromCommand<typeof backupDownloadDef>,
171
+ ) {
172
+ const backups = yield* useBackupsManager(
173
+ (m) => m.list(),
174
+ 'Error listing backups',
175
+ );
176
+
177
+ if (backups.length === 0) {
178
+ yield* Effect.log('No backups yet.');
179
+ return;
180
+ }
181
+
182
+ const backup = yield* pickBackup(backups, backupId, opts);
183
+
184
+ const outPath = path.resolve(opts.out ?? backupZipName(backup));
185
+ // Catch this before the download runs, not at the final rename.
186
+ if (existsSync(outPath) && statSync(outPath).isDirectory()) {
187
+ return yield* BadArgsError.make({
188
+ message: `${outPath} is a directory.`,
189
+ });
190
+ }
191
+
192
+ yield* renderBackupsTable([backup]);
193
+ const sizes = estimateZipSize(backup);
194
+ if (sizes) {
195
+ yield* Effect.log(
196
+ `The zip file will be between ${formatFileSize(sizes.min)} and ${formatFileSize(sizes.max)}, depending on the compression ratio.`,
197
+ );
198
+ }
199
+ yield* Effect.log(chalk.dim(`Saving to ${outPath} (pass -o to change).`));
200
+
201
+ const ok = yield* promptOk({ promptText: 'Download this backup?' });
202
+ if (!ok) return;
203
+
204
+ if (existsSync(outPath)) {
205
+ const overwrite = yield* promptOk({
206
+ promptText: `${path.basename(outPath)} already exists. Overwrite?`,
207
+ });
208
+ if (!overwrite) return;
209
+ }
210
+
211
+ const manager = yield* buildBackupsManager;
212
+
213
+ const result = yield* Effect.tryPromise({
214
+ try: () => runDownload(manager, backup, outPath),
215
+ catch: (e) =>
216
+ new PlatformApiError({ message: 'Error downloading backup', cause: e }),
217
+ });
218
+
219
+ if (result === null) {
220
+ yield* Effect.log('Download cancelled.');
221
+ return;
222
+ }
223
+
224
+ const filesPart =
225
+ result.files > 0
226
+ ? ` and ${result.files.toLocaleString()} storage files`
227
+ : '';
228
+ yield* Effect.log(
229
+ `Saved ${result.entities.toLocaleString()} namespaces${filesPart} (${formatFileSize(result.zipBytes)})`,
230
+ );
231
+ });