@superlayer/cli 1.0.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +202 -0
- package/NOTICE +4 -0
- package/README.md +67 -0
- package/bin/index.js +3 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +103 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/commands/app/delete.d.ts +7 -0
- package/dist/commands/app/delete.d.ts.map +1 -0
- package/dist/commands/app/delete.js +57 -0
- package/dist/commands/app/delete.js.map +1 -0
- package/dist/commands/app/list.d.ts +6 -0
- package/dist/commands/app/list.d.ts.map +1 -0
- package/dist/commands/app/list.js +29 -0
- package/dist/commands/app/list.js.map +1 -0
- package/dist/commands/auth/client/add.d.ts +9 -0
- package/dist/commands/auth/client/add.d.ts.map +1 -0
- package/dist/commands/auth/client/add.js +409 -0
- package/dist/commands/auth/client/add.js.map +1 -0
- package/dist/commands/auth/client/delete.d.ts +11 -0
- package/dist/commands/auth/client/delete.d.ts.map +1 -0
- package/dist/commands/auth/client/delete.js +48 -0
- package/dist/commands/auth/client/delete.js.map +1 -0
- package/dist/commands/auth/client/list.d.ts +6 -0
- package/dist/commands/auth/client/list.d.ts.map +1 -0
- package/dist/commands/auth/client/list.js +38 -0
- package/dist/commands/auth/client/list.js.map +1 -0
- package/dist/commands/auth/client/shared.d.ts +70 -0
- package/dist/commands/auth/client/shared.d.ts.map +1 -0
- package/dist/commands/auth/client/shared.js +140 -0
- package/dist/commands/auth/client/shared.js.map +1 -0
- package/dist/commands/auth/client/update.d.ts +8 -0
- package/dist/commands/auth/client/update.d.ts.map +1 -0
- package/dist/commands/auth/client/update.js +445 -0
- package/dist/commands/auth/client/update.js.map +1 -0
- package/dist/commands/auth/email/pull.d.ts +24 -0
- package/dist/commands/auth/email/pull.d.ts.map +1 -0
- package/dist/commands/auth/email/pull.js +100 -0
- package/dist/commands/auth/email/pull.js.map +1 -0
- package/dist/commands/auth/email/push.d.ts +8 -0
- package/dist/commands/auth/email/push.d.ts.map +1 -0
- package/dist/commands/auth/email/push.js +58 -0
- package/dist/commands/auth/email/push.js.map +1 -0
- package/dist/commands/auth/email/resend.d.ts +3 -0
- package/dist/commands/auth/email/resend.d.ts.map +1 -0
- package/dist/commands/auth/email/resend.js +7 -0
- package/dist/commands/auth/email/resend.js.map +1 -0
- package/dist/commands/auth/email/reset.d.ts +5 -0
- package/dist/commands/auth/email/reset.d.ts.map +1 -0
- package/dist/commands/auth/email/reset.js +25 -0
- package/dist/commands/auth/email/reset.js.map +1 -0
- package/dist/commands/auth/email/status.d.ts +57 -0
- package/dist/commands/auth/email/status.d.ts.map +1 -0
- package/dist/commands/auth/email/status.js +96 -0
- package/dist/commands/auth/email/status.js.map +1 -0
- package/dist/commands/auth/email/verify.d.ts +5 -0
- package/dist/commands/auth/email/verify.d.ts.map +1 -0
- package/dist/commands/auth/email/verify.js +12 -0
- package/dist/commands/auth/email/verify.js.map +1 -0
- package/dist/commands/auth/origin/add.d.ts +12 -0
- package/dist/commands/auth/origin/add.d.ts.map +1 -0
- package/dist/commands/auth/origin/add.js +153 -0
- package/dist/commands/auth/origin/add.js.map +1 -0
- package/dist/commands/auth/origin/delete.d.ts +8 -0
- package/dist/commands/auth/origin/delete.d.ts.map +1 -0
- package/dist/commands/auth/origin/delete.js +38 -0
- package/dist/commands/auth/origin/delete.js.map +1 -0
- package/dist/commands/auth/origin/list.d.ts +9 -0
- package/dist/commands/auth/origin/list.d.ts.map +1 -0
- package/dist/commands/auth/origin/list.js +52 -0
- package/dist/commands/auth/origin/list.js.map +1 -0
- package/dist/commands/backup/download.d.ts +10 -0
- package/dist/commands/backup/download.d.ts.map +1 -0
- package/dist/commands/backup/download.js +174 -0
- package/dist/commands/backup/download.js.map +1 -0
- package/dist/commands/backup/list.d.ts +11 -0
- package/dist/commands/backup/list.d.ts.map +1 -0
- package/dist/commands/backup/list.js +74 -0
- package/dist/commands/backup/list.js.map +1 -0
- package/dist/commands/claim.d.ts +6 -0
- package/dist/commands/claim.d.ts.map +1 -0
- package/dist/commands/claim.js +22 -0
- package/dist/commands/claim.js.map +1 -0
- package/dist/commands/explorer.d.ts +6 -0
- package/dist/commands/explorer.d.ts.map +1 -0
- package/dist/commands/explorer.js +13 -0
- package/dist/commands/explorer.js.map +1 -0
- package/dist/commands/info.d.ts +9 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +41 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +41 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/initWithoutFiles.d.ts +6 -0
- package/dist/commands/initWithoutFiles.d.ts.map +1 -0
- package/dist/commands/initWithoutFiles.js +64 -0
- package/dist/commands/initWithoutFiles.js.map +1 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +44 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +14 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/pull.d.ts +5 -0
- package/dist/commands/pull.d.ts.map +1 -0
- package/dist/commands/pull.js +15 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/push.d.ts +6 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +20 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/query.d.ts +7 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +52 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/webhooks/add.d.ts +9 -0
- package/dist/commands/webhooks/add.d.ts.map +1 -0
- package/dist/commands/webhooks/add.js +75 -0
- package/dist/commands/webhooks/add.js.map +1 -0
- package/dist/commands/webhooks/delete.d.ts +6 -0
- package/dist/commands/webhooks/delete.d.ts.map +1 -0
- package/dist/commands/webhooks/delete.js +17 -0
- package/dist/commands/webhooks/delete.js.map +1 -0
- package/dist/commands/webhooks/disable.d.ts +7 -0
- package/dist/commands/webhooks/disable.d.ts.map +1 -0
- package/dist/commands/webhooks/disable.js +18 -0
- package/dist/commands/webhooks/disable.js.map +1 -0
- package/dist/commands/webhooks/enable.d.ts +6 -0
- package/dist/commands/webhooks/enable.d.ts.map +1 -0
- package/dist/commands/webhooks/enable.js +18 -0
- package/dist/commands/webhooks/enable.js.map +1 -0
- package/dist/commands/webhooks/events/list.d.ts +7 -0
- package/dist/commands/webhooks/events/list.d.ts.map +1 -0
- package/dist/commands/webhooks/events/list.js +31 -0
- package/dist/commands/webhooks/events/list.js.map +1 -0
- package/dist/commands/webhooks/events/payload.d.ts +8 -0
- package/dist/commands/webhooks/events/payload.d.ts.map +1 -0
- package/dist/commands/webhooks/events/payload.js +39 -0
- package/dist/commands/webhooks/events/payload.js.map +1 -0
- package/dist/commands/webhooks/events/resend.d.ts +8 -0
- package/dist/commands/webhooks/events/resend.d.ts.map +1 -0
- package/dist/commands/webhooks/events/resend.js +43 -0
- package/dist/commands/webhooks/events/resend.js.map +1 -0
- package/dist/commands/webhooks/list.d.ts +8 -0
- package/dist/commands/webhooks/list.d.ts.map +1 -0
- package/dist/commands/webhooks/list.js +29 -0
- package/dist/commands/webhooks/list.js.map +1 -0
- package/dist/commands/webhooks/shared.d.ts +40 -0
- package/dist/commands/webhooks/shared.d.ts.map +1 -0
- package/dist/commands/webhooks/shared.js +248 -0
- package/dist/commands/webhooks/shared.js.map +1 -0
- package/dist/commands/webhooks/update.d.ts +10 -0
- package/dist/commands/webhooks/update.d.ts.map +1 -0
- package/dist/commands/webhooks/update.js +189 -0
- package/dist/commands/webhooks/update.js.map +1 -0
- package/dist/context/authToken.d.ts +29 -0
- package/dist/context/authToken.d.ts.map +1 -0
- package/dist/context/authToken.js +73 -0
- package/dist/context/authToken.js.map +1 -0
- package/dist/context/currentApp.d.ts +38 -0
- package/dist/context/currentApp.d.ts.map +1 -0
- package/dist/context/currentApp.js +222 -0
- package/dist/context/currentApp.js.map +1 -0
- package/dist/context/globalOpts.d.ts +11 -0
- package/dist/context/globalOpts.d.ts.map +1 -0
- package/dist/context/globalOpts.js +13 -0
- package/dist/context/globalOpts.js.map +1 -0
- package/dist/context/platformApi.d.ts +19 -0
- package/dist/context/platformApi.d.ts.map +1 -0
- package/dist/context/platformApi.js +24 -0
- package/dist/context/platformApi.js.map +1 -0
- package/dist/context/projectInfo.d.ts +30 -0
- package/dist/context/projectInfo.d.ts.map +1 -0
- package/dist/context/projectInfo.js +152 -0
- package/dist/context/projectInfo.js.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +6 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +714 -0
- package/dist/index.js.map +1 -0
- package/dist/layer.d.ts +25 -0
- package/dist/layer.d.ts.map +1 -0
- package/dist/layer.js +119 -0
- package/dist/layer.js.map +1 -0
- package/dist/lib/args.d.ts +212 -0
- package/dist/lib/args.d.ts.map +1 -0
- package/dist/lib/args.js +313 -0
- package/dist/lib/args.js.map +1 -0
- package/dist/lib/backupDownload.d.ts +21 -0
- package/dist/lib/backupDownload.d.ts.map +1 -0
- package/dist/lib/backupDownload.js +151 -0
- package/dist/lib/backupDownload.js.map +1 -0
- package/dist/lib/backups.d.ts +12 -0
- package/dist/lib/backups.d.ts.map +1 -0
- package/dist/lib/backups.js +26 -0
- package/dist/lib/backups.js.map +1 -0
- package/dist/lib/config.d.ts +6 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +39 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/createApp.d.ts +12 -0
- package/dist/lib/createApp.d.ts.map +1 -0
- package/dist/lib/createApp.js +15 -0
- package/dist/lib/createApp.js.map +1 -0
- package/dist/lib/email.d.ts +47 -0
- package/dist/lib/email.d.ts.map +1 -0
- package/dist/lib/email.js +71 -0
- package/dist/lib/email.js.map +1 -0
- package/dist/lib/handleEnv.d.ts +7 -0
- package/dist/lib/handleEnv.d.ts.map +1 -0
- package/dist/lib/handleEnv.js +99 -0
- package/dist/lib/handleEnv.js.map +1 -0
- package/dist/lib/http.d.ts +30 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +55 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/login.d.ts +12 -0
- package/dist/lib/login.d.ts.map +1 -0
- package/dist/lib/login.js +38 -0
- package/dist/lib/login.js.map +1 -0
- package/dist/lib/oauth.d.ts +306 -0
- package/dist/lib/oauth.d.ts.map +1 -0
- package/dist/lib/oauth.js +195 -0
- package/dist/lib/oauth.js.map +1 -0
- package/dist/lib/platformApi.d.ts +5 -0
- package/dist/lib/platformApi.d.ts.map +1 -0
- package/dist/lib/platformApi.js +11 -0
- package/dist/lib/platformApi.js.map +1 -0
- package/dist/lib/pullPerms.d.ts +7 -0
- package/dist/lib/pullPerms.d.ts.map +1 -0
- package/dist/lib/pullPerms.js +41 -0
- package/dist/lib/pullPerms.js.map +1 -0
- package/dist/lib/pullSchema.d.ts +12 -0
- package/dist/lib/pullSchema.d.ts.map +1 -0
- package/dist/lib/pullSchema.js +62 -0
- package/dist/lib/pullSchema.js.map +1 -0
- package/dist/lib/pushPerms.d.ts +13 -0
- package/dist/lib/pushPerms.d.ts.map +1 -0
- package/dist/lib/pushPerms.js +54 -0
- package/dist/lib/pushPerms.js.map +1 -0
- package/dist/lib/pushSchema.d.ts +53 -0
- package/dist/lib/pushSchema.d.ts.map +1 -0
- package/dist/lib/pushSchema.js +165 -0
- package/dist/lib/pushSchema.js.map +1 -0
- package/dist/lib/ui.d.ts +18 -0
- package/dist/lib/ui.d.ts.map +1 -0
- package/dist/lib/ui.js +32 -0
- package/dist/lib/ui.js.map +1 -0
- package/dist/lib/webhooks.d.ts +27 -0
- package/dist/lib/webhooks.d.ts.map +1 -0
- package/dist/lib/webhooks.js +95 -0
- package/dist/lib/webhooks.js.map +1 -0
- package/dist/logging.d.ts +5 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +25 -0
- package/dist/logging.js.map +1 -0
- package/dist/old.d.ts +17 -0
- package/dist/old.d.ts.map +1 -0
- package/dist/old.js +410 -0
- package/dist/old.js.map +1 -0
- package/dist/program.d.ts +3 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +3 -0
- package/dist/program.js.map +1 -0
- package/dist/renderSchemaPlan.d.ts +19 -0
- package/dist/renderSchemaPlan.d.ts.map +1 -0
- package/dist/renderSchemaPlan.js +220 -0
- package/dist/renderSchemaPlan.js.map +1 -0
- package/dist/ui/index.d.ts +292 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +1296 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/lib.d.ts +124 -0
- package/dist/ui/lib.d.ts.map +1 -0
- package/dist/ui/lib.js +333 -0
- package/dist/ui/lib.js.map +1 -0
- package/dist/util/findConfigCandidates.d.ts +13 -0
- package/dist/util/findConfigCandidates.d.ts.map +1 -0
- package/dist/util/findConfigCandidates.js +211 -0
- package/dist/util/findConfigCandidates.js.map +1 -0
- package/dist/util/fs.d.ts +4 -0
- package/dist/util/fs.d.ts.map +1 -0
- package/dist/util/fs.js +22 -0
- package/dist/util/fs.js.map +1 -0
- package/dist/util/getAppName.d.ts +5 -0
- package/dist/util/getAppName.d.ts.map +1 -0
- package/dist/util/getAppName.js +14 -0
- package/dist/util/getAppName.js.map +1 -0
- package/dist/util/instantConfig.d.ts +9 -0
- package/dist/util/instantConfig.d.ts.map +1 -0
- package/dist/util/instantConfig.js +13 -0
- package/dist/util/instantConfig.js.map +1 -0
- package/dist/util/isHeadlessEnvironment.d.ts +4 -0
- package/dist/util/isHeadlessEnvironment.d.ts.map +1 -0
- package/dist/util/isHeadlessEnvironment.js +11 -0
- package/dist/util/isHeadlessEnvironment.js.map +1 -0
- package/dist/util/loadConfig.d.ts +3 -0
- package/dist/util/loadConfig.d.ts.map +1 -0
- package/dist/util/loadConfig.js +72 -0
- package/dist/util/loadConfig.js.map +1 -0
- package/dist/util/loadEnv.d.ts +2 -0
- package/dist/util/loadEnv.d.ts.map +1 -0
- package/dist/util/loadEnv.js +10 -0
- package/dist/util/loadEnv.js.map +1 -0
- package/dist/util/mergeSchema.d.ts +10 -0
- package/dist/util/mergeSchema.d.ts.map +1 -0
- package/dist/util/mergeSchema.js +338 -0
- package/dist/util/mergeSchema.js.map +1 -0
- package/dist/util/projectDir.d.ts +7 -0
- package/dist/util/projectDir.d.ts.map +1 -0
- package/dist/util/projectDir.js +43 -0
- package/dist/util/projectDir.js.map +1 -0
- package/dist/util/renamePrompt.d.ts +15 -0
- package/dist/util/renamePrompt.d.ts.map +1 -0
- package/dist/util/renamePrompt.js +57 -0
- package/dist/util/renamePrompt.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/package.json +96 -0
package/dist/lib/args.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Args lets commands read CLI flags as a small pipeline:
|
|
3
|
+
*
|
|
4
|
+
* 1. Parse a value from opts
|
|
5
|
+
* 2. Gate it: when is this flag available?
|
|
6
|
+
* 3. Prompt for a missing value, when interactive
|
|
7
|
+
* 4. Validate and finish as required or optional
|
|
8
|
+
*
|
|
9
|
+
* This keeps the "can this flag be used here?" logic next to the value it
|
|
10
|
+
* controls. For example, a Google client secret is only meaningful when using
|
|
11
|
+
* custom web credentials:
|
|
12
|
+
*
|
|
13
|
+
* const clientSecret = yield* Args.text(opts, 'client-secret').pipe(
|
|
14
|
+
* Args.availableWhen(usesCustomWebCredentials),
|
|
15
|
+
* Args.prompt(clientSecretPrompt({ providerUrl })),
|
|
16
|
+
* Args.required(),
|
|
17
|
+
* );
|
|
18
|
+
*
|
|
19
|
+
* The key argument to text/bool/has is the exact opts lookup key. If the
|
|
20
|
+
* user-facing flag name differs, pass simpleName for errors:
|
|
21
|
+
*
|
|
22
|
+
* Args.text(opts, 'customRedirectUri', { simpleName: '--custom-redirect-uri' })
|
|
23
|
+
*/
|
|
24
|
+
import { Effect } from 'effect';
|
|
25
|
+
import { pipeArguments } from 'effect/Pipeable';
|
|
26
|
+
import { BadArgsError } from "../errors.js";
|
|
27
|
+
import { GlobalOpts } from "../context/globalOpts.js";
|
|
28
|
+
import { UI } from "../ui/index.js";
|
|
29
|
+
import { runUIEffect } from "./ui.js";
|
|
30
|
+
const makeArg = (flag, state) => {
|
|
31
|
+
const arg = {
|
|
32
|
+
flag,
|
|
33
|
+
state,
|
|
34
|
+
pipe() {
|
|
35
|
+
return pipeArguments(this, arguments);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
return arg;
|
|
39
|
+
};
|
|
40
|
+
const active = (value, provided) => ({ _tag: 'Active', provided, value });
|
|
41
|
+
const inactive = { _tag: 'Inactive' };
|
|
42
|
+
const missingMessage = (flag) => `Missing required value for ${flag}`;
|
|
43
|
+
/**
|
|
44
|
+
* @example
|
|
45
|
+
* if (Args.has(opts, 'custom-redirect-uri')) {
|
|
46
|
+
* // The user explicitly passed --custom-redirect-uri.
|
|
47
|
+
* }
|
|
48
|
+
*/
|
|
49
|
+
function has(opts, key) {
|
|
50
|
+
return Object.prototype.hasOwnProperty.call(opts, key);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @example
|
|
54
|
+
* const configureWeb = Args.hasAny(opts, [
|
|
55
|
+
* 'team-id',
|
|
56
|
+
* 'key-id',
|
|
57
|
+
* 'private-key-file',
|
|
58
|
+
* ]);
|
|
59
|
+
*/
|
|
60
|
+
function hasAny(opts, keys) {
|
|
61
|
+
return keys.some((key) => has(opts, key));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns true only for boolean true or the string "true".
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const useDevCredentials = Args.isTrue(opts, 'dev-credentials');
|
|
68
|
+
*/
|
|
69
|
+
function isTrue(opts, key) {
|
|
70
|
+
const value = opts[key];
|
|
71
|
+
return value === true || value === 'true';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Starts a string arg pipeline. Strings are trimmed, numbers are stringified,
|
|
75
|
+
* empty values become missing values, and other types produce BadArgsError.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const clientId = yield* Args.text(opts, 'client-id').pipe(
|
|
79
|
+
* Args.prompt(clientIdPrompt({ providerUrl })),
|
|
80
|
+
* Args.required(),
|
|
81
|
+
* );
|
|
82
|
+
*/
|
|
83
|
+
function text(opts, key, options) {
|
|
84
|
+
const flag = options?.simpleName ?? `--${key}`;
|
|
85
|
+
const provided = Object.prototype.hasOwnProperty.call(opts, key);
|
|
86
|
+
return makeArg(flag, Effect.succeed(active(readTextValue(opts[key], flag), provided)));
|
|
87
|
+
}
|
|
88
|
+
function readTextValue(value, flag) {
|
|
89
|
+
return Effect.gen(function* readTextValue() {
|
|
90
|
+
if (value === undefined || value === null)
|
|
91
|
+
return undefined;
|
|
92
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
93
|
+
const trimmed = String(value).trim();
|
|
94
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
95
|
+
}
|
|
96
|
+
return yield* BadArgsError.make({
|
|
97
|
+
message: `Invalid value for ${flag}`,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Starts a boolean arg pipeline. Accepts booleans and the strings "true" or
|
|
103
|
+
* "false"; other supplied values produce BadArgsError.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* const configureWeb = yield* Args.bool(opts, 'configure-web').pipe(
|
|
107
|
+
* Args.confirm({ promptText: 'Configure web redirect flow?' }),
|
|
108
|
+
* Args.required(),
|
|
109
|
+
* );
|
|
110
|
+
*/
|
|
111
|
+
function bool(opts, key, options) {
|
|
112
|
+
const flag = options?.simpleName ?? `--${key}`;
|
|
113
|
+
const provided = Object.prototype.hasOwnProperty.call(opts, key);
|
|
114
|
+
return makeArg(flag, Effect.succeed(active(readBooleanValue(opts[key], flag), provided)));
|
|
115
|
+
}
|
|
116
|
+
function readBooleanValue(value, flag) {
|
|
117
|
+
return Effect.gen(function* readBooleanValue() {
|
|
118
|
+
if (value === undefined || value === null)
|
|
119
|
+
return undefined;
|
|
120
|
+
if (value === true || value === 'true')
|
|
121
|
+
return true;
|
|
122
|
+
if (value === false || value === 'false')
|
|
123
|
+
return false;
|
|
124
|
+
return yield* BadArgsError.make({
|
|
125
|
+
message: `Invalid value for ${flag}`,
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function uiErrorToBadArgs(e) {
|
|
130
|
+
return BadArgsError.make({ message: `UI error: ${e.message}` });
|
|
131
|
+
}
|
|
132
|
+
function mapActive(wrapper, mapValue) {
|
|
133
|
+
return makeArg(wrapper.flag, Effect.gen(function* mapArgState() {
|
|
134
|
+
const state = yield* wrapper.state;
|
|
135
|
+
if (state._tag === 'Inactive')
|
|
136
|
+
return inactive;
|
|
137
|
+
return active(mapValue(state.value), state.provided);
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Gates an arg behind a mode or earlier choice.
|
|
142
|
+
*
|
|
143
|
+
* If the condition is false and the user supplied the flag, this returns an
|
|
144
|
+
* error.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* const clientSecret = yield* Args.text(opts, 'client-secret').pipe(
|
|
148
|
+
* Args.availableWhen(appType === 'web'),
|
|
149
|
+
* Args.prompt(clientSecretPrompt({ providerUrl })),
|
|
150
|
+
* Args.required(),
|
|
151
|
+
* );
|
|
152
|
+
*/
|
|
153
|
+
function availableWhen(condition, options) {
|
|
154
|
+
return function availableWhenArg(arg) {
|
|
155
|
+
return makeArg(arg.flag, Effect.gen(function* gateArgAvailability() {
|
|
156
|
+
const state = yield* arg.state;
|
|
157
|
+
if (condition || state._tag === 'Inactive')
|
|
158
|
+
return state;
|
|
159
|
+
if (state.provided) {
|
|
160
|
+
return yield* BadArgsError.make({
|
|
161
|
+
message: options?.message ??
|
|
162
|
+
`${arg.flag} is not compatible with other options`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return inactive;
|
|
166
|
+
}));
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Prompts for a missing text value.
|
|
171
|
+
*
|
|
172
|
+
* With --yes, the prompt is skipped. If inputProps.defaultValue is set, that
|
|
173
|
+
* value is used. Otherwise the value stays missing.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* const clientName = yield* Args.text(opts, 'name').pipe(
|
|
177
|
+
* Args.prompt({
|
|
178
|
+
* prompt: 'Client Name:',
|
|
179
|
+
* defaultValue: suggestedClientName,
|
|
180
|
+
* }),
|
|
181
|
+
* Args.required(),
|
|
182
|
+
* );
|
|
183
|
+
*/
|
|
184
|
+
function prompt(inputProps) {
|
|
185
|
+
return function promptArg(arg) {
|
|
186
|
+
return mapActive(arg, (valueEffect) => Effect.gen(function* promptWhenMissing() {
|
|
187
|
+
const value = yield* valueEffect;
|
|
188
|
+
if (value !== undefined)
|
|
189
|
+
return value;
|
|
190
|
+
const { yes } = yield* GlobalOpts;
|
|
191
|
+
const result = yes
|
|
192
|
+
? inputProps.defaultValue
|
|
193
|
+
: yield* runUIEffect(new UI.TextInput(inputProps)).pipe(Effect.catchTag('UIError', uiErrorToBadArgs));
|
|
194
|
+
if (result === undefined)
|
|
195
|
+
return undefined;
|
|
196
|
+
const trimmed = result.trim();
|
|
197
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
198
|
+
}));
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Prompts for a missing boolean value.
|
|
203
|
+
*
|
|
204
|
+
* With --yes, the prompt is skipped and confirmationProps.defaultValue is used.
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* const configureWeb = yield* Args.bool(opts, 'configure-web').pipe(
|
|
208
|
+
* Args.confirm({
|
|
209
|
+
* promptText: 'Configure web redirect flow?',
|
|
210
|
+
* defaultValue: false,
|
|
211
|
+
* }),
|
|
212
|
+
* Args.required(),
|
|
213
|
+
* );
|
|
214
|
+
*/
|
|
215
|
+
function confirm(confirmationProps) {
|
|
216
|
+
return function confirmArg(arg) {
|
|
217
|
+
return mapActive(arg, (valueEffect) => Effect.gen(function* confirmWhenMissing() {
|
|
218
|
+
const value = yield* valueEffect;
|
|
219
|
+
if (value !== undefined)
|
|
220
|
+
return value;
|
|
221
|
+
const { yes } = yield* GlobalOpts;
|
|
222
|
+
if (yes)
|
|
223
|
+
return confirmationProps.defaultValue;
|
|
224
|
+
return yield* runUIEffect(new UI.Confirmation(confirmationProps)).pipe(Effect.catchTag('UIError', uiErrorToBadArgs));
|
|
225
|
+
}));
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Validates a present value. Return an error message to fail, or undefined to
|
|
230
|
+
* accept the value. Missing and inactive args pass through unchanged.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* const projectId = yield* Args.text(opts, 'project-id').pipe(
|
|
234
|
+
* Args.prompt(firebaseProjectIdPrompt({})),
|
|
235
|
+
* Args.validate(validateFirebaseProjectId),
|
|
236
|
+
* Args.required(),
|
|
237
|
+
* );
|
|
238
|
+
*/
|
|
239
|
+
function validate(validator) {
|
|
240
|
+
return function validateArg(arg) {
|
|
241
|
+
return mapActive(arg, (valueEffect) => Effect.gen(function* validateValue() {
|
|
242
|
+
const value = yield* valueEffect;
|
|
243
|
+
if (value === undefined)
|
|
244
|
+
return undefined;
|
|
245
|
+
const message = validator(value);
|
|
246
|
+
if (!message)
|
|
247
|
+
return value;
|
|
248
|
+
return yield* BadArgsError.make({ message });
|
|
249
|
+
}));
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Finishes a pipeline with a required value.
|
|
254
|
+
*
|
|
255
|
+
* Missing active args produce BadArgsError. Inactive args return undefined, so
|
|
256
|
+
* callers can skip downstream work for unavailable flags.
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* const clientId = yield* Args.text(opts, 'client-id').pipe(
|
|
260
|
+
* Args.prompt(clientIdPrompt({ providerUrl })),
|
|
261
|
+
* Args.required(),
|
|
262
|
+
* );
|
|
263
|
+
*/
|
|
264
|
+
function required(options) {
|
|
265
|
+
return function requiredArg(arg) {
|
|
266
|
+
return Effect.gen(function* requireValue() {
|
|
267
|
+
const state = yield* arg.state;
|
|
268
|
+
if (state._tag === 'Inactive')
|
|
269
|
+
return undefined;
|
|
270
|
+
const value = yield* state.value;
|
|
271
|
+
if (value !== undefined)
|
|
272
|
+
return value;
|
|
273
|
+
return yield* BadArgsError.make({
|
|
274
|
+
message: options?.message ?? missingMessage(arg.flag),
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Finishes a pipeline with an optional value.
|
|
281
|
+
*
|
|
282
|
+
* Missing and inactive args return undefined.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(
|
|
286
|
+
* Args.prompt(optionalRedirectPrompt),
|
|
287
|
+
* Args.optional(),
|
|
288
|
+
* );
|
|
289
|
+
*/
|
|
290
|
+
function optional() {
|
|
291
|
+
return function optionalArg(arg) {
|
|
292
|
+
return Effect.gen(function* optionalValue() {
|
|
293
|
+
const state = yield* arg.state;
|
|
294
|
+
if (state._tag === 'Inactive')
|
|
295
|
+
return undefined;
|
|
296
|
+
return yield* state.value;
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
export const Args = {
|
|
301
|
+
text,
|
|
302
|
+
bool,
|
|
303
|
+
has,
|
|
304
|
+
hasAny,
|
|
305
|
+
isTrue,
|
|
306
|
+
availableWhen,
|
|
307
|
+
prompt,
|
|
308
|
+
confirm,
|
|
309
|
+
validate,
|
|
310
|
+
required,
|
|
311
|
+
optional,
|
|
312
|
+
};
|
|
313
|
+
//# sourceMappingURL=args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/lib/args.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Args lets commands read CLI flags as a small pipeline:\n *\n * 1. Parse a value from opts\n * 2. Gate it: when is this flag available?\n * 3. Prompt for a missing value, when interactive\n * 4. Validate and finish as required or optional\n *\n * This keeps the \"can this flag be used here?\" logic next to the value it\n * controls. For example, a Google client secret is only meaningful when using\n * custom web credentials:\n *\n * const clientSecret = yield* Args.text(opts, 'client-secret').pipe(\n * Args.availableWhen(usesCustomWebCredentials),\n * Args.prompt(clientSecretPrompt({ providerUrl })),\n * Args.required(),\n * );\n *\n * The key argument to text/bool/has is the exact opts lookup key. If the\n * user-facing flag name differs, pass simpleName for errors:\n *\n * Args.text(opts, 'customRedirectUri', { simpleName: '--custom-redirect-uri' })\n */\nimport { Effect } from 'effect';\nimport { pipeArguments, type Pipeable } from 'effect/Pipeable';\nimport { BadArgsError } from '../errors.ts';\nimport { GlobalOpts } from '../context/globalOpts.ts';\nimport { UI } from '../ui/index.ts';\nimport { runUIEffect } from './ui.ts';\n\ntype ActiveArg<A, E, R> = {\n readonly _tag: 'Active';\n readonly provided: boolean;\n readonly value: Effect.Effect<A | undefined, E, R>;\n};\n\ntype InactiveArg = {\n readonly _tag: 'Inactive';\n};\n\ntype ArgState<A, E, R, CanBeInactive extends boolean> =\n | ActiveArg<A, E, R>\n | (CanBeInactive extends true ? InactiveArg : never);\n\n/**\n * A parsed CLI arg that can be composed with Args helpers.\n *\n * Commands usually create one with text() or bool(), then finish with\n * required() or optional().\n *\n * @example\n * const name = yield* Args.text(opts, 'name').pipe(\n * Args.prompt({ prompt: 'Client Name:' }),\n * Args.required(),\n * );\n */\nexport interface Arg<\n A,\n E = never,\n R = never,\n CanBeInactive extends boolean = false,\n> extends Pipeable {\n readonly flag: string;\n readonly state: Effect.Effect<ArgState<A, E, R, CanBeInactive>, E, R>;\n}\n\nexport type ArgOptions = {\n /**\n * Use when the opts key is not the user-facing flag name.\n *\n * @example\n * Args.text(opts, 'customRedirectUri', {\n * simpleName: '--custom-redirect-uri',\n * })\n */\n simpleName?: string;\n};\n\nconst makeArg = <A, E, R, CanBeInactive extends boolean>(\n flag: string,\n state: Effect.Effect<ArgState<A, E, R, CanBeInactive>, E, R>,\n): Arg<A, E, R, CanBeInactive> => {\n const arg: Arg<A, E, R, CanBeInactive> = {\n flag,\n state,\n pipe() {\n return pipeArguments(this, arguments);\n },\n };\n return arg;\n};\n\nconst active = <A, E, R>(\n value: Effect.Effect<A | undefined, E, R>,\n provided: boolean,\n): ActiveArg<A, E, R> => ({ _tag: 'Active', provided, value });\n\nconst inactive: InactiveArg = { _tag: 'Inactive' };\n\nconst missingMessage = (flag: string) => `Missing required value for ${flag}`;\n\ntype MissingOptions = {\n message?: string;\n};\n\ntype UnavailableOptions = {\n message?: string;\n};\n\n/**\n * @example\n * if (Args.has(opts, 'custom-redirect-uri')) {\n * // The user explicitly passed --custom-redirect-uri.\n * }\n */\nfunction has(opts: Record<string, unknown>, key: string) {\n return Object.prototype.hasOwnProperty.call(opts, key);\n}\n\n/**\n * @example\n * const configureWeb = Args.hasAny(opts, [\n * 'team-id',\n * 'key-id',\n * 'private-key-file',\n * ]);\n */\nfunction hasAny(opts: Record<string, unknown>, keys: string[]) {\n return keys.some((key) => has(opts, key));\n}\n\n/**\n * Returns true only for boolean true or the string \"true\".\n *\n * @example\n * const useDevCredentials = Args.isTrue(opts, 'dev-credentials');\n */\nfunction isTrue(opts: Record<string, unknown>, key: string) {\n const value = opts[key];\n return value === true || value === 'true';\n}\n\n/**\n * Starts a string arg pipeline. Strings are trimmed, numbers are stringified,\n * empty values become missing values, and other types produce BadArgsError.\n *\n * @example\n * const clientId = yield* Args.text(opts, 'client-id').pipe(\n * Args.prompt(clientIdPrompt({ providerUrl })),\n * Args.required(),\n * );\n */\nfunction text(\n opts: Record<string, unknown>,\n key: string,\n options?: ArgOptions,\n): Arg<string, BadArgsError> {\n const flag = options?.simpleName ?? `--${key}`;\n const provided = Object.prototype.hasOwnProperty.call(opts, key);\n\n return makeArg(\n flag,\n Effect.succeed(active(readTextValue(opts[key], flag), provided)),\n );\n}\n\nfunction readTextValue(value: unknown, flag: string) {\n return Effect.gen(function* readTextValue() {\n if (value === undefined || value === null) return undefined;\n\n if (typeof value === 'string' || typeof value === 'number') {\n const trimmed = String(value).trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n\n return yield* BadArgsError.make({\n message: `Invalid value for ${flag}`,\n });\n });\n}\n\n/**\n * Starts a boolean arg pipeline. Accepts booleans and the strings \"true\" or\n * \"false\"; other supplied values produce BadArgsError.\n *\n * @example\n * const configureWeb = yield* Args.bool(opts, 'configure-web').pipe(\n * Args.confirm({ promptText: 'Configure web redirect flow?' }),\n * Args.required(),\n * );\n */\nfunction bool(\n opts: Record<string, unknown>,\n key: string,\n options?: ArgOptions,\n): Arg<boolean, BadArgsError> {\n const flag = options?.simpleName ?? `--${key}`;\n const provided = Object.prototype.hasOwnProperty.call(opts, key);\n\n return makeArg(\n flag,\n Effect.succeed(active(readBooleanValue(opts[key], flag), provided)),\n );\n}\n\nfunction readBooleanValue(value: unknown, flag: string) {\n return Effect.gen(function* readBooleanValue() {\n if (value === undefined || value === null) return undefined;\n if (value === true || value === 'true') return true;\n if (value === false || value === 'false') return false;\n\n return yield* BadArgsError.make({\n message: `Invalid value for ${flag}`,\n });\n });\n}\n\nfunction uiErrorToBadArgs(e: { message: string }) {\n return BadArgsError.make({ message: `UI error: ${e.message}` });\n}\n\nfunction mapActive<A, B, E, R, E2, R2, CanBeInactive extends boolean>(\n wrapper: Arg<A, E, R, CanBeInactive>,\n mapValue: (\n value: Effect.Effect<A | undefined, E, R>,\n ) => Effect.Effect<B | undefined, E | E2, R | R2>,\n): Arg<B, E | E2, R | R2, CanBeInactive> {\n return makeArg(\n wrapper.flag,\n Effect.gen(function* mapArgState() {\n const state = yield* wrapper.state;\n if (state._tag === 'Inactive') return inactive;\n return active(mapValue(state.value), state.provided);\n }) as Effect.Effect<\n ArgState<B, E | E2, R | R2, CanBeInactive>,\n E | E2,\n R | R2\n >,\n );\n}\n\n/**\n * Gates an arg behind a mode or earlier choice.\n *\n * If the condition is false and the user supplied the flag, this returns an\n * error.\n *\n * @example\n * const clientSecret = yield* Args.text(opts, 'client-secret').pipe(\n * Args.availableWhen(appType === 'web'),\n * Args.prompt(clientSecretPrompt({ providerUrl })),\n * Args.required(),\n * );\n */\nfunction availableWhen(condition: boolean, options?: UnavailableOptions) {\n return function availableWhenArg<A, E, R, CanBeInactive extends boolean>(\n arg: Arg<A, E, R, CanBeInactive>,\n ) {\n return makeArg<A, E | BadArgsError, R, true>(\n arg.flag,\n Effect.gen(function* gateArgAvailability() {\n const state = yield* arg.state;\n if (condition || state._tag === 'Inactive') return state;\n if (state.provided) {\n return yield* BadArgsError.make({\n message:\n options?.message ??\n `${arg.flag} is not compatible with other options`,\n });\n }\n return inactive;\n }),\n );\n };\n}\n\n/**\n * Prompts for a missing text value.\n *\n * With --yes, the prompt is skipped. If inputProps.defaultValue is set, that\n * value is used. Otherwise the value stays missing.\n *\n * @example\n * const clientName = yield* Args.text(opts, 'name').pipe(\n * Args.prompt({\n * prompt: 'Client Name:',\n * defaultValue: suggestedClientName,\n * }),\n * Args.required(),\n * );\n */\nfunction prompt(inputProps: UI.TextInputProps) {\n return function promptArg<E, R, CanBeInactive extends boolean>(\n arg: Arg<string, E, R, CanBeInactive>,\n ): Arg<string, E | BadArgsError, R | GlobalOpts, CanBeInactive> {\n return mapActive(arg, (valueEffect) =>\n Effect.gen(function* promptWhenMissing() {\n const value = yield* valueEffect;\n if (value !== undefined) return value;\n\n const { yes } = yield* GlobalOpts;\n const result = yes\n ? inputProps.defaultValue\n : yield* runUIEffect(new UI.TextInput(inputProps)).pipe(\n Effect.catchTag('UIError', uiErrorToBadArgs),\n );\n if (result === undefined) return undefined;\n\n const trimmed = result.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }),\n );\n };\n}\n\n/**\n * Prompts for a missing boolean value.\n *\n * With --yes, the prompt is skipped and confirmationProps.defaultValue is used.\n *\n * @example\n * const configureWeb = yield* Args.bool(opts, 'configure-web').pipe(\n * Args.confirm({\n * promptText: 'Configure web redirect flow?',\n * defaultValue: false,\n * }),\n * Args.required(),\n * );\n */\nfunction confirm(confirmationProps: UI.ConfirmationProps) {\n return function confirmArg<E, R, CanBeInactive extends boolean>(\n arg: Arg<boolean, E, R, CanBeInactive>,\n ): Arg<boolean, E | BadArgsError, R | GlobalOpts, CanBeInactive> {\n return mapActive(arg, (valueEffect) =>\n Effect.gen(function* confirmWhenMissing() {\n const value = yield* valueEffect;\n if (value !== undefined) return value;\n\n const { yes } = yield* GlobalOpts;\n if (yes) return confirmationProps.defaultValue;\n\n return yield* runUIEffect(new UI.Confirmation(confirmationProps)).pipe(\n Effect.catchTag('UIError', uiErrorToBadArgs),\n );\n }),\n );\n };\n}\n\n/**\n * Validates a present value. Return an error message to fail, or undefined to\n * accept the value. Missing and inactive args pass through unchanged.\n *\n * @example\n * const projectId = yield* Args.text(opts, 'project-id').pipe(\n * Args.prompt(firebaseProjectIdPrompt({})),\n * Args.validate(validateFirebaseProjectId),\n * Args.required(),\n * );\n */\nfunction validate<A>(validator: (value: A) => string | undefined) {\n return function validateArg<E, R, CanBeInactive extends boolean>(\n arg: Arg<A, E, R, CanBeInactive>,\n ): Arg<A, E | BadArgsError, R, CanBeInactive> {\n return mapActive(arg, (valueEffect) =>\n Effect.gen(function* validateValue() {\n const value = yield* valueEffect;\n if (value === undefined) return undefined;\n\n const message = validator(value);\n if (!message) return value;\n\n return yield* BadArgsError.make({ message });\n }),\n );\n };\n}\n\n/**\n * Finishes a pipeline with a required value.\n *\n * Missing active args produce BadArgsError. Inactive args return undefined, so\n * callers can skip downstream work for unavailable flags.\n *\n * @example\n * const clientId = yield* Args.text(opts, 'client-id').pipe(\n * Args.prompt(clientIdPrompt({ providerUrl })),\n * Args.required(),\n * );\n */\nfunction required(options?: MissingOptions) {\n return function requiredArg<A, E, R, CanBeInactive extends boolean>(\n arg: Arg<A, E, R, CanBeInactive>,\n ): Effect.Effect<\n CanBeInactive extends true ? A | undefined : A,\n E | BadArgsError,\n R\n > {\n return Effect.gen(function* requireValue() {\n const state = yield* arg.state;\n if (state._tag === 'Inactive') return undefined;\n\n const value = yield* state.value;\n if (value !== undefined) return value;\n\n return yield* BadArgsError.make({\n message: options?.message ?? missingMessage(arg.flag),\n });\n }) as Effect.Effect<\n CanBeInactive extends true ? A | undefined : A,\n E | BadArgsError,\n R\n >;\n };\n}\n\n/**\n * Finishes a pipeline with an optional value.\n *\n * Missing and inactive args return undefined.\n *\n * @example\n * const customRedirectUri = yield* Args.text(opts, 'custom-redirect-uri').pipe(\n * Args.prompt(optionalRedirectPrompt),\n * Args.optional(),\n * );\n */\nfunction optional() {\n return function optionalArg<A, E, R, CanBeInactive extends boolean>(\n arg: Arg<A, E, R, CanBeInactive>,\n ) {\n return Effect.gen(function* optionalValue() {\n const state = yield* arg.state;\n if (state._tag === 'Inactive') return undefined;\n\n return yield* state.value;\n });\n };\n}\n\nexport const Args = {\n text,\n bool,\n has,\n hasAny,\n isTrue,\n availableWhen,\n prompt,\n confirm,\n validate,\n required,\n optional,\n};\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AppBackup, BackupDownloadProgress, BackupDownloadResult, BackupsManager } from '@superlayer/platform';
|
|
2
|
+
export type { BackupDownloadProgress, BackupDownloadResult, } from '@superlayer/platform';
|
|
3
|
+
/**
|
|
4
|
+
* Downloads a backup into a zip file at `outPath` via the shared
|
|
5
|
+
* `BackupsManager.downloadArchive` pipeline, supplying the Node-specific
|
|
6
|
+
* pieces:
|
|
7
|
+
* presigned URLs are fetched with node:http(s) and decompressed explicitly,
|
|
8
|
+
* and the archive streams to disk with backpressure so memory stays flat
|
|
9
|
+
* regardless of backup size.
|
|
10
|
+
*
|
|
11
|
+
* Writes to `<outPath>.partial` and renames on success; a failed or aborted
|
|
12
|
+
* download removes the partial file.
|
|
13
|
+
*/
|
|
14
|
+
export declare function downloadBackupToFile(opts: {
|
|
15
|
+
manager: BackupsManager;
|
|
16
|
+
backup: AppBackup;
|
|
17
|
+
outPath: string;
|
|
18
|
+
signal: AbortSignal;
|
|
19
|
+
onProgress: (progress: BackupDownloadProgress) => void;
|
|
20
|
+
}): Promise<BackupDownloadResult>;
|
|
21
|
+
//# sourceMappingURL=backupDownload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backupDownload.d.ts","sourceRoot":"","sources":["../../src/lib/backupDownload.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,SAAS,EAET,sBAAsB,EACtB,oBAAoB,EACpB,cAAc,EACf,MAAM,sBAAsB,CAAC;AAM9B,YAAY,EACV,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAuG9B;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACxD,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA4ChC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createWriteStream } from 'node:fs';
|
|
2
|
+
import { open, rename, unlink } from 'node:fs/promises';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
import { once } from 'node:events';
|
|
5
|
+
import { get as httpGet } from 'node:http';
|
|
6
|
+
import { get as httpsGet } from 'node:https';
|
|
7
|
+
import { Readable, Writable } from 'node:stream';
|
|
8
|
+
import zlib from 'node:zlib';
|
|
9
|
+
import version from '../version.js';
|
|
10
|
+
// Set a user-agent or else cloudfront might block the request
|
|
11
|
+
const userAgent = `instant-cli/${version}`;
|
|
12
|
+
// zstd landed in node:zlib in 22.15 / 23.8; on older Nodes the property is
|
|
13
|
+
// absent, so feature-detect instead of assuming the type declarations match
|
|
14
|
+
// the runtime.
|
|
15
|
+
const createZstdDecompress = zlib.createZstdDecompress;
|
|
16
|
+
function fetchStream(url, signal) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
const get = url.startsWith('https:') ? httpsGet : httpGet;
|
|
19
|
+
const req = get(url, { signal, headers: { 'user-agent': userAgent } }, resolve);
|
|
20
|
+
req.on('error', reject);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
// .pipe doesn't forward errors, so a source failure would otherwise leave the
|
|
24
|
+
// destination (and the zip writer reading from it) hanging forever.
|
|
25
|
+
function pipe(src, dst) {
|
|
26
|
+
src.on('error', (e) => dst.destroy(e));
|
|
27
|
+
return src.pipe(dst);
|
|
28
|
+
}
|
|
29
|
+
// S3/CloudFront answer a rejected presigned URL with a short XML body naming
|
|
30
|
+
// the actual cause (SignatureDoesNotMatch, AccessDenied, expired, …). Read a
|
|
31
|
+
// bounded prefix so the error surfaces the reason instead of a bare status.
|
|
32
|
+
async function readErrorBody(res, signal) {
|
|
33
|
+
// A stalled or dribbling error body must not hang the download; destroying
|
|
34
|
+
// res ends the read below. The request's own signal already tears res down
|
|
35
|
+
// on a caller abort, so this only guards the no-abort stall.
|
|
36
|
+
const timer = setTimeout(() => res.destroy(), 5000);
|
|
37
|
+
try {
|
|
38
|
+
const chunks = [];
|
|
39
|
+
let total = 0;
|
|
40
|
+
for await (const chunk of res) {
|
|
41
|
+
chunks.push(chunk);
|
|
42
|
+
total += chunk.length;
|
|
43
|
+
if (total >= 2048)
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
return Buffer.concat(chunks)
|
|
47
|
+
.toString('utf8')
|
|
48
|
+
.replace(/\s+/g, ' ')
|
|
49
|
+
.trim()
|
|
50
|
+
.slice(0, 500);
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
// A caller-initiated abort must propagate, not be masked as an empty body;
|
|
54
|
+
// only other read failures fall back to no reason.
|
|
55
|
+
if (signal.aborted)
|
|
56
|
+
throw e;
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
res.destroy();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Fetches a presigned URL with node:http(s), decompressing explicitly: the
|
|
65
|
+
// entity shards are served with `Content-Encoding: zstd` and Node doesn't
|
|
66
|
+
// auto-decompress that. downloadBackupToFile refuses to run without zstd
|
|
67
|
+
// support, so the assertion below can't fire.
|
|
68
|
+
async function fetchBody(url, signal) {
|
|
69
|
+
const res = await fetchStream(url, signal);
|
|
70
|
+
if (res.statusCode !== 200) {
|
|
71
|
+
const body = await readErrorBody(res, signal);
|
|
72
|
+
throw new Error(`HTTP ${res.statusCode}${body ? ` — ${body}` : ''}`);
|
|
73
|
+
}
|
|
74
|
+
const encoding = res.headers['content-encoding'];
|
|
75
|
+
let stream = res;
|
|
76
|
+
if (encoding === 'zstd') {
|
|
77
|
+
stream = pipe(stream, createZstdDecompress());
|
|
78
|
+
}
|
|
79
|
+
else if (encoding === 'gzip') {
|
|
80
|
+
stream = pipe(stream, zlib.createGunzip());
|
|
81
|
+
}
|
|
82
|
+
else if (encoding) {
|
|
83
|
+
res.destroy();
|
|
84
|
+
throw new Error(`Unsupported content encoding: ${encoding}`);
|
|
85
|
+
}
|
|
86
|
+
return Readable.toWeb(stream);
|
|
87
|
+
}
|
|
88
|
+
async function createZipWriter(sink, signal) {
|
|
89
|
+
// Loaded on demand so every other CLI command skips parsing it.
|
|
90
|
+
const { ZipWriter } = await import('@zip.js/zip.js');
|
|
91
|
+
// zip64: without it any archive whose central-directory offset passes 4GB
|
|
92
|
+
// writes a wrapped 32-bit offset and the zip is unreadable.
|
|
93
|
+
return new ZipWriter(sink, { zip64: true, signal });
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Downloads a backup into a zip file at `outPath` via the shared
|
|
97
|
+
* `BackupsManager.downloadArchive` pipeline, supplying the Node-specific
|
|
98
|
+
* pieces:
|
|
99
|
+
* presigned URLs are fetched with node:http(s) and decompressed explicitly,
|
|
100
|
+
* and the archive streams to disk with backpressure so memory stays flat
|
|
101
|
+
* regardless of backup size.
|
|
102
|
+
*
|
|
103
|
+
* Writes to `<outPath>.partial` and renames on success; a failed or aborted
|
|
104
|
+
* download removes the partial file.
|
|
105
|
+
*/
|
|
106
|
+
export async function downloadBackupToFile(opts) {
|
|
107
|
+
// The entity shards are served with `Content-Encoding: zstd`; fail before
|
|
108
|
+
// writing anything if this Node can't decompress them.
|
|
109
|
+
if (!createZstdDecompress) {
|
|
110
|
+
throw new Error('Downloading backups requires Node 22.15 or newer (for zstd support).');
|
|
111
|
+
}
|
|
112
|
+
// Randomized so a stale partial or a concurrent download of the same
|
|
113
|
+
// backup can't collide; 'wx' turns any remaining collision into an error
|
|
114
|
+
// instead of silently truncating another run's file.
|
|
115
|
+
const partialPath = `${opts.outPath}.partial-${randomBytes(4).toString('hex')}`;
|
|
116
|
+
const fileStream = createWriteStream(partialPath, { flags: 'wx' });
|
|
117
|
+
const awaitFileClosed = async () => {
|
|
118
|
+
if (!fileStream.closed)
|
|
119
|
+
await once(fileStream, 'close');
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
const result = await opts.manager.downloadArchive({
|
|
123
|
+
backup: opts.backup,
|
|
124
|
+
fetchBody,
|
|
125
|
+
sink: Writable.toWeb(fileStream),
|
|
126
|
+
createWriter: createZipWriter,
|
|
127
|
+
signal: opts.signal,
|
|
128
|
+
onProgress: opts.onProgress,
|
|
129
|
+
});
|
|
130
|
+
await awaitFileClosed();
|
|
131
|
+
// Flush to disk before the rename so a crash right after can't leave a
|
|
132
|
+
// complete-looking zip with unwritten tails.
|
|
133
|
+
const fh = await open(partialPath, 'r+');
|
|
134
|
+
try {
|
|
135
|
+
await fh.sync();
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
await fh.close();
|
|
139
|
+
}
|
|
140
|
+
await rename(partialPath, opts.outPath);
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
// The pipeline already aborted the sink; wait for the fd to close, then
|
|
145
|
+
// discard the partial file on disk.
|
|
146
|
+
await awaitFileClosed().catch(() => { });
|
|
147
|
+
await unlink(partialPath).catch(() => { });
|
|
148
|
+
throw e;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=backupDownload.js.map
|
|
@@ -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 '@superlayer/platform';\nimport version from '../version.js';\n\n// Set a user-agent or else cloudfront might block the request\nconst userAgent = `instant-cli/${version}`;\n\nexport type {\n BackupDownloadProgress,\n BackupDownloadResult,\n} from '@superlayer/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(\n url,\n { signal, headers: { 'user-agent': userAgent } },\n resolve,\n );\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// S3/CloudFront answer a rejected presigned URL with a short XML body naming\n// the actual cause (SignatureDoesNotMatch, AccessDenied, expired, …). Read a\n// bounded prefix so the error surfaces the reason instead of a bare status.\nasync function readErrorBody(\n res: IncomingMessage,\n signal: AbortSignal,\n): Promise<string> {\n // A stalled or dribbling error body must not hang the download; destroying\n // res ends the read below. The request's own signal already tears res down\n // on a caller abort, so this only guards the no-abort stall.\n const timer = setTimeout(() => res.destroy(), 5000);\n try {\n const chunks: Buffer[] = [];\n let total = 0;\n for await (const chunk of res) {\n chunks.push(chunk as Buffer);\n total += (chunk as Buffer).length;\n if (total >= 2048) break;\n }\n return Buffer.concat(chunks)\n .toString('utf8')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, 500);\n } catch (e) {\n // A caller-initiated abort must propagate, not be masked as an empty body;\n // only other read failures fall back to no reason.\n if (signal.aborted) throw e;\n return '';\n } finally {\n clearTimeout(timer);\n res.destroy();\n }\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 const body = await readErrorBody(res, signal);\n throw new Error(`HTTP ${res.statusCode}${body ? ` — ${body}` : ''}`);\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 '@superlayer/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,sBAAsB,CAAC;AAC3D,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 '@superlayer/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,6 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { BadArgsError } from '../errors.ts';
|
|
3
|
+
export declare const getBaseUrl: Effect.Effect<string, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, never>;
|
|
4
|
+
export declare const getOAuthCallbackUrl: Effect.Effect<string, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, never>;
|
|
5
|
+
export declare const getDashUrl: Effect.Effect<string, BadArgsError | import("effect/Cause").UnknownException | import("effect/ConfigError").ConfigError, never>;
|
|
6
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAkB,MAAM,QAAQ,CAAC;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAY5C,eAAO,MAAM,UAAU,iIA0BrB,CAAC;AAEH,eAAO,MAAM,mBAAmB,iIAE/B,CAAC;AAEF,eAAO,MAAM,UAAU,iIA0BrB,CAAC"}
|