@better-update/cli 0.28.1 → 0.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +236 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -34,7 +34,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
34
34
|
|
|
35
35
|
//#endregion
|
|
36
36
|
//#region package.json
|
|
37
|
-
var version = "0.
|
|
37
|
+
var version = "0.29.1";
|
|
38
38
|
|
|
39
39
|
//#endregion
|
|
40
40
|
//#region src/lib/interactive-mode.ts
|
|
@@ -904,7 +904,7 @@ var AssetsGroup = class extends HttpApiGroup.make("assets").add(HttpApiEndpoint.
|
|
|
904
904
|
|
|
905
905
|
//#endregion
|
|
906
906
|
//#region ../../packages/api/src/domain/audit-log.ts
|
|
907
|
-
const AuditLogResourceType = Schema.Literal("project", "branch", "channel", "update", "build", "appleCredential", "androidCredential", "iosBundleConfiguration", "envVar", "device", "webhook", "iosAppMetadata", "submission", "vaultAccess", "policy", "group", "policyAttachment", "apiKey", "invitation", "member", "organization");
|
|
907
|
+
const AuditLogResourceType = Schema.Literal("project", "branch", "channel", "update", "environment", "build", "appleCredential", "androidCredential", "iosBundleConfiguration", "envVar", "device", "webhook", "iosAppMetadata", "submission", "vaultAccess", "policy", "group", "policyAttachment", "apiKey", "invitation", "member", "organization");
|
|
908
908
|
const AuditLogSource = Schema.Literal("session", "api-key");
|
|
909
909
|
var AuditLog = class extends Schema.Class("AuditLog")({
|
|
910
910
|
id: Id,
|
|
@@ -941,6 +941,7 @@ var Branch = class extends Schema.Class("Branch")({
|
|
|
941
941
|
id: Id,
|
|
942
942
|
projectId: Id,
|
|
943
943
|
name: Schema.String,
|
|
944
|
+
isBuiltin: Schema.Boolean,
|
|
944
945
|
createdAt: DateTimeString,
|
|
945
946
|
updateCount: Schema.Number
|
|
946
947
|
}) {};
|
|
@@ -1231,6 +1232,7 @@ var Channel = class extends Schema.Class("Channel")({
|
|
|
1231
1232
|
branchMappingJson: Schema.NullOr(Schema.String),
|
|
1232
1233
|
cacheVersion: Schema.Number,
|
|
1233
1234
|
isPaused: Schema.Boolean,
|
|
1235
|
+
isBuiltin: Schema.Boolean,
|
|
1234
1236
|
createdAt: DateTimeString
|
|
1235
1237
|
}) {};
|
|
1236
1238
|
const ChannelSortColumn = Schema.Literal("name", "createdAt");
|
|
@@ -1381,11 +1383,32 @@ var DevicesGroup = class extends HttpApiGroup.make("devices").add(HttpApiEndpoin
|
|
|
1381
1383
|
description: "Apple device management for ad-hoc builds"
|
|
1382
1384
|
})) {};
|
|
1383
1385
|
|
|
1386
|
+
//#endregion
|
|
1387
|
+
//#region ../../packages/api/src/domain/environment.ts
|
|
1388
|
+
/**
|
|
1389
|
+
* An environment name: lowercase letters, digits and hyphens, starting with a
|
|
1390
|
+
* letter. Shared by the env-var `environment` axis and the environment entity so
|
|
1391
|
+
* a custom environment name and an env var's `environment` use one shape.
|
|
1392
|
+
*/
|
|
1393
|
+
const EnvironmentName = Schema.String.pipe(Schema.pattern(/^[a-z][a-z0-9-]*$/u), Schema.maxLength(64));
|
|
1394
|
+
/** An organization environment: a built-in (virtual) or a user-defined row. */
|
|
1395
|
+
var Environment = class extends Schema.Class("Environment")({
|
|
1396
|
+
id: Id,
|
|
1397
|
+
organizationId: Id,
|
|
1398
|
+
name: EnvironmentName,
|
|
1399
|
+
isBuiltin: Schema.Boolean,
|
|
1400
|
+
createdAt: DateTimeString
|
|
1401
|
+
}) {};
|
|
1402
|
+
const EnvironmentListResult = Schema.Struct({ items: Schema.Array(Environment) });
|
|
1403
|
+
const CreateEnvironmentBody = Schema.Struct({ name: EnvironmentName });
|
|
1404
|
+
const RenameEnvironmentBody = Schema.Struct({ name: EnvironmentName });
|
|
1405
|
+
const DeleteEnvironmentResult = Schema.Struct({ deleted: Schema.Number });
|
|
1406
|
+
|
|
1384
1407
|
//#endregion
|
|
1385
1408
|
//#region ../../packages/api/src/domain/env-var.ts
|
|
1386
1409
|
const EnvVarVisibility = Schema.Literal("plaintext", "sensitive");
|
|
1387
1410
|
const EnvVarScope = Schema.Literal("project", "global");
|
|
1388
|
-
const EnvVarEnvironment =
|
|
1411
|
+
const EnvVarEnvironment = EnvironmentName;
|
|
1389
1412
|
const EnvVarListScope = Schema.Literal("all", "project", "global");
|
|
1390
1413
|
/**
|
|
1391
1414
|
* A client-sealed env var value. `id` is the revision UUID the CLI bound as the
|
|
@@ -1519,6 +1542,27 @@ var EnvVarsGroup = class extends HttpApiGroup.make("env-vars").add(HttpApiEndpoi
|
|
|
1519
1542
|
description: "Manage end-to-end encrypted, versioned environment variables for project builds"
|
|
1520
1543
|
})) {};
|
|
1521
1544
|
|
|
1545
|
+
//#endregion
|
|
1546
|
+
//#region ../../packages/api/src/groups/environments.ts
|
|
1547
|
+
/** `:name` path parameter — the environment name (built-in or user-defined). */
|
|
1548
|
+
const nameParam = HttpApiSchema.param("name", Schema.String);
|
|
1549
|
+
var EnvironmentsGroup = class extends HttpApiGroup.make("environments").add(HttpApiEndpoint.get("list", "/api/environments").addSuccess(EnvironmentListResult).annotateContext(OpenApi.annotations({
|
|
1550
|
+
title: "List environments",
|
|
1551
|
+
description: "List the organization's environments: the three built-ins (development, preview, production) followed by user-defined ones."
|
|
1552
|
+
}))).add(HttpApiEndpoint.post("create", "/api/environments").setPayload(CreateEnvironmentBody).addSuccess(Environment, { status: 201 }).addError(Conflict).addError(BadRequest).annotateContext(OpenApi.annotations({
|
|
1553
|
+
title: "Create environment",
|
|
1554
|
+
description: "Create a user-defined environment for the organization. Built-in names are reserved."
|
|
1555
|
+
}))).add(HttpApiEndpoint.patch("rename")`/api/environments/${nameParam}`.setPayload(RenameEnvironmentBody).addSuccess(Environment).addError(Conflict).addError(BadRequest).annotateContext(OpenApi.annotations({
|
|
1556
|
+
title: "Rename environment",
|
|
1557
|
+
description: "Rename a user-defined environment. Built-ins cannot be renamed. Env vars referencing the old name are re-pointed at the new name."
|
|
1558
|
+
}))).add(HttpApiEndpoint.del("delete")`/api/environments/${nameParam}`.addSuccess(DeleteEnvironmentResult).addError(Conflict).annotateContext(OpenApi.annotations({
|
|
1559
|
+
title: "Delete environment",
|
|
1560
|
+
description: "Delete a user-defined environment. Built-ins cannot be deleted, nor can an environment still referenced by env vars."
|
|
1561
|
+
}))).addError(NotFound).addError(Conflict).addError(BadRequest).addError(Forbidden).annotateContext(OpenApi.annotations({
|
|
1562
|
+
title: "Environments",
|
|
1563
|
+
description: "Organization environment management endpoints"
|
|
1564
|
+
})) {};
|
|
1565
|
+
|
|
1522
1566
|
//#endregion
|
|
1523
1567
|
//#region ../../packages/api/src/domain/update.ts
|
|
1524
1568
|
var Update = class extends Schema.Class("Update")({
|
|
@@ -2434,7 +2478,7 @@ var WebhooksGroup = class extends HttpApiGroup.make("webhooks").add(HttpApiEndpo
|
|
|
2434
2478
|
|
|
2435
2479
|
//#endregion
|
|
2436
2480
|
//#region ../../packages/api/src/api.ts
|
|
2437
|
-
var ManagementApi = class extends HttpApi.make("management-api").add(ProjectsGroup).add(BranchesGroup).add(ChannelsGroup).add(UpdatesGroup).add(AssetsGroup).add(AnalyticsGroup).add(BuildsGroup).add(EnvVarsGroup).add(FingerprintsGroup).add(AuditLogsGroup).add(DevicesGroup).add(AppleTeamsGroup).add(AppleDistributionCertificatesGroup).add(ApplePushKeysGroup).add(AscApiKeysGroup).add(AppleProvisioningProfilesGroup).add(GoogleServiceAccountKeysGroup).add(IosBundleConfigurationsGroup).add(IosAppMetadataGroup).add(SubmissionsGroup).add(AndroidApplicationIdentifiersGroup).add(AndroidUploadKeystoresGroup).add(AndroidBuildCredentialsGroup).add(BuildCredentialsGroup).add(UserEncryptionKeysGroup).add(OrgVaultGroup).add(MeGroup).add(WebhooksGroup).add(PoliciesGroup).add(GroupsGroup).add(PolicyAttachmentsGroup).add(ApiKeysGroup).add(InvitationsGroup).add(MembersGroup).add(OrganizationGroup).add(AdminGroup).middleware(Authentication).annotateContext(OpenApi.annotations({
|
|
2481
|
+
var ManagementApi = class extends HttpApi.make("management-api").add(ProjectsGroup).add(BranchesGroup).add(ChannelsGroup).add(EnvironmentsGroup).add(UpdatesGroup).add(AssetsGroup).add(AnalyticsGroup).add(BuildsGroup).add(EnvVarsGroup).add(FingerprintsGroup).add(AuditLogsGroup).add(DevicesGroup).add(AppleTeamsGroup).add(AppleDistributionCertificatesGroup).add(ApplePushKeysGroup).add(AscApiKeysGroup).add(AppleProvisioningProfilesGroup).add(GoogleServiceAccountKeysGroup).add(IosBundleConfigurationsGroup).add(IosAppMetadataGroup).add(SubmissionsGroup).add(AndroidApplicationIdentifiersGroup).add(AndroidUploadKeystoresGroup).add(AndroidBuildCredentialsGroup).add(BuildCredentialsGroup).add(UserEncryptionKeysGroup).add(OrgVaultGroup).add(MeGroup).add(WebhooksGroup).add(PoliciesGroup).add(GroupsGroup).add(PolicyAttachmentsGroup).add(ApiKeysGroup).add(InvitationsGroup).add(MembersGroup).add(OrganizationGroup).add(AdminGroup).middleware(Authentication).annotateContext(OpenApi.annotations({
|
|
2438
2482
|
title: "Better Update Management API",
|
|
2439
2483
|
version: "1.0.0",
|
|
2440
2484
|
description: "Management API for OTA update publishing, deployment, and analytics"
|
|
@@ -4789,7 +4833,7 @@ const parseLimit = (raw, defaultValue) => {
|
|
|
4789
4833
|
|
|
4790
4834
|
//#endregion
|
|
4791
4835
|
//#region src/commands/audit-logs/list.ts
|
|
4792
|
-
const listCommand$
|
|
4836
|
+
const listCommand$10 = defineCommand({
|
|
4793
4837
|
meta: {
|
|
4794
4838
|
name: "list",
|
|
4795
4839
|
description: "List audit log entries"
|
|
@@ -4851,7 +4895,7 @@ const auditLogsCommand = defineCommand({
|
|
|
4851
4895
|
name: "audit-logs",
|
|
4852
4896
|
description: "View audit logs"
|
|
4853
4897
|
},
|
|
4854
|
-
subCommands: { list: listCommand$
|
|
4898
|
+
subCommands: { list: listCommand$10 }
|
|
4855
4899
|
});
|
|
4856
4900
|
|
|
4857
4901
|
//#endregion
|
|
@@ -4955,7 +4999,7 @@ const drainPages = (fetchPage) => {
|
|
|
4955
4999
|
|
|
4956
5000
|
//#endregion
|
|
4957
5001
|
//#region src/commands/branches.ts
|
|
4958
|
-
const listCommand$
|
|
5002
|
+
const listCommand$9 = defineCommand({
|
|
4959
5003
|
meta: {
|
|
4960
5004
|
name: "list",
|
|
4961
5005
|
description: "List branches for the linked project"
|
|
@@ -4978,7 +5022,7 @@ const listCommand$8 = defineCommand({
|
|
|
4978
5022
|
]), "No branches found.");
|
|
4979
5023
|
}))
|
|
4980
5024
|
});
|
|
4981
|
-
const createCommand$
|
|
5025
|
+
const createCommand$5 = defineCommand({
|
|
4982
5026
|
meta: {
|
|
4983
5027
|
name: "create",
|
|
4984
5028
|
description: "Create a branch"
|
|
@@ -5033,7 +5077,7 @@ const viewCommand$3 = defineCommand({
|
|
|
5033
5077
|
return branch;
|
|
5034
5078
|
}), { json: "value" })
|
|
5035
5079
|
});
|
|
5036
|
-
const renameCommand$
|
|
5080
|
+
const renameCommand$2 = defineCommand({
|
|
5037
5081
|
meta: {
|
|
5038
5082
|
name: "rename",
|
|
5039
5083
|
description: "Rename a branch"
|
|
@@ -5059,7 +5103,7 @@ const renameCommand$1 = defineCommand({
|
|
|
5059
5103
|
return branch;
|
|
5060
5104
|
}), { json: "value" })
|
|
5061
5105
|
});
|
|
5062
|
-
const deleteCommand$
|
|
5106
|
+
const deleteCommand$7 = defineCommand({
|
|
5063
5107
|
meta: {
|
|
5064
5108
|
name: "delete",
|
|
5065
5109
|
description: "Delete a branch"
|
|
@@ -5084,11 +5128,11 @@ const branchesCommand = defineCommand({
|
|
|
5084
5128
|
description: "Manage branches"
|
|
5085
5129
|
},
|
|
5086
5130
|
subCommands: {
|
|
5087
|
-
list: listCommand$
|
|
5131
|
+
list: listCommand$9,
|
|
5088
5132
|
view: viewCommand$3,
|
|
5089
|
-
create: createCommand$
|
|
5090
|
-
rename: renameCommand$
|
|
5091
|
-
delete: deleteCommand$
|
|
5133
|
+
create: createCommand$5,
|
|
5134
|
+
rename: renameCommand$2,
|
|
5135
|
+
delete: deleteCommand$7
|
|
5092
5136
|
}
|
|
5093
5137
|
});
|
|
5094
5138
|
|
|
@@ -18882,15 +18926,6 @@ const grantRecipient = (args) => Effect.gen(function* () {
|
|
|
18882
18926
|
} });
|
|
18883
18927
|
});
|
|
18884
18928
|
/**
|
|
18885
|
-
* Resolve the passphrase needed to unlock the active identity before a crypto
|
|
18886
|
-
* operation: prompt for it when the identity is the on-disk file, or return
|
|
18887
|
-
* `undefined` when the raw `BETTER_UPDATE_IDENTITY` env key is in use (CI). The
|
|
18888
|
-
* resolved value is threaded into {@link unlockVaultKey} by the cipher helpers.
|
|
18889
|
-
*/
|
|
18890
|
-
const resolveVaultPassphrase = Effect.gen(function* () {
|
|
18891
|
-
return (yield* activeRecipient).source === "file" ? yield* promptPassword("Passphrase to unlock this device's identity:") : void 0;
|
|
18892
|
-
});
|
|
18893
|
-
/**
|
|
18894
18929
|
* Unlock the org vault key for an interactive command, reusing a cached vault key
|
|
18895
18930
|
* from the OS keychain when one is present and unexpired — so the device
|
|
18896
18931
|
* passphrase is prompted at most once per cache TTL rather than on every command
|
|
@@ -18898,6 +18933,12 @@ const resolveVaultPassphrase = Effect.gen(function* () {
|
|
|
18898
18933
|
* The CI `BETTER_UPDATE_IDENTITY` key carries no passphrase and is never cached:
|
|
18899
18934
|
* it skips straight to the raw unwrap. On a cache miss the full unlock runs —
|
|
18900
18935
|
* prompt, Argon2id, fetch + unwrap — and the result is cached for next time.
|
|
18936
|
+
*
|
|
18937
|
+
* The cached key is the unwrapped vault key, which both unwraps (decrypt/read)
|
|
18938
|
+
* and wraps (encrypt/write) DEKs — so this single entry point backs every vault
|
|
18939
|
+
* operation: download/build-resolve reads, seal-for-upload + generate writes, and
|
|
18940
|
+
* rotation. There is no read-only cache: an unlock makes the next write seamless
|
|
18941
|
+
* too.
|
|
18901
18942
|
*/
|
|
18902
18943
|
const unlockVaultKeyInteractive = (api) => Effect.gen(function* () {
|
|
18903
18944
|
const recipient = yield* activeRecipient;
|
|
@@ -18909,6 +18950,17 @@ const unlockVaultKeyInteractive = (api) => Effect.gen(function* () {
|
|
|
18909
18950
|
yield* cache.set(recipient.publicKey, vault);
|
|
18910
18951
|
return vault;
|
|
18911
18952
|
}).pipe(Effect.provide(VaultCacheLive));
|
|
18953
|
+
/**
|
|
18954
|
+
* Forget the active recipient's cached vault key. Called after a rotation re-keys
|
|
18955
|
+
* the vault: the cached key + version are now stale, so leaving them would make
|
|
18956
|
+
* the next seal upload a key/version the server CAS-rejects (and the next decrypt
|
|
18957
|
+
* fail integrity). Clearing forces a fresh unlock at the new version next time —
|
|
18958
|
+
* which also correctly locks out a device that just revoked its own access.
|
|
18959
|
+
*/
|
|
18960
|
+
const forgetCachedVaultKey = Effect.gen(function* () {
|
|
18961
|
+
const recipient = yield* activeRecipient;
|
|
18962
|
+
yield* (yield* VaultCache).clear(recipient.publicKey);
|
|
18963
|
+
}).pipe(Effect.provide(VaultCacheLive));
|
|
18912
18964
|
/** Look up a registered recipient by its key id or full `SHA256:` fingerprint. */
|
|
18913
18965
|
const findRecipient = (api, selector) => Effect.gen(function* () {
|
|
18914
18966
|
const { items } = yield* api.userEncryptionKeys.list();
|
|
@@ -18948,13 +19000,6 @@ const getActiveOrgId = (api) => Effect.gen(function* () {
|
|
|
18948
19000
|
if (me.activeOrganization === null) return yield* new IdentityError({ message: "No active organization for this token." });
|
|
18949
19001
|
return me.activeOrganization.id;
|
|
18950
19002
|
});
|
|
18951
|
-
/** Resolve the active org id and unlock this device's vault key — the once-per-command I/O. */
|
|
18952
|
-
const openVaultSession = (api, passphrase) => Effect.gen(function* () {
|
|
18953
|
-
return {
|
|
18954
|
-
orgId: yield* getActiveOrgId(api),
|
|
18955
|
-
vault: yield* unlockVaultKey(api, passphrase)
|
|
18956
|
-
};
|
|
18957
|
-
});
|
|
18958
19003
|
/**
|
|
18959
19004
|
* {@link openVaultSession} that unlocks the vault key interactively — reusing the
|
|
18960
19005
|
* OS-keychain-cached key when one is live (no prompt), prompting for the device
|
|
@@ -19566,7 +19611,7 @@ const generateAndUploadKeystore = (api, input) => Effect.scoped(Effect.gen(funct
|
|
|
19566
19611
|
...compact({ validityDays: input.validityDays })
|
|
19567
19612
|
});
|
|
19568
19613
|
const bytes = yield* fs.readFile(keystorePath);
|
|
19569
|
-
const session = yield*
|
|
19614
|
+
const session = yield* openVaultSessionInteractive(api);
|
|
19570
19615
|
const metadata = { keyAlias: input.keyAlias };
|
|
19571
19616
|
const envelope = yield* sealForUpload({
|
|
19572
19617
|
session,
|
|
@@ -19617,7 +19662,7 @@ const generateAndUploadDistributionCertificate = (api, input) => Effect.gen(func
|
|
|
19617
19662
|
step: "p12-build",
|
|
19618
19663
|
message: cause.message
|
|
19619
19664
|
})));
|
|
19620
|
-
const session = yield*
|
|
19665
|
+
const session = yield* openVaultSessionInteractive(api);
|
|
19621
19666
|
const metadata = {
|
|
19622
19667
|
serialNumber: bundle.metadata.serialNumber,
|
|
19623
19668
|
appleTeamIdentifier: bundle.metadata.appleTeamId,
|
|
@@ -20623,7 +20668,7 @@ const generateAndUploadDistributionCertificateViaAppleId = (api, input) => Effec
|
|
|
20623
20668
|
step: "parse-p12",
|
|
20624
20669
|
message: cause.message
|
|
20625
20670
|
})));
|
|
20626
|
-
const session = yield*
|
|
20671
|
+
const session = yield* openVaultSessionInteractive(api);
|
|
20627
20672
|
const envelopeMetadata = {
|
|
20628
20673
|
serialNumber: metadata.serialNumber,
|
|
20629
20674
|
appleTeamIdentifier: metadata.appleTeamId,
|
|
@@ -21021,14 +21066,12 @@ const isMissingResolveError = (cause) => hasTag(cause) && (cause._tag === "NotFo
|
|
|
21021
21066
|
const randomKeystoreSecret = () => randomBytes(24).toString("base64url");
|
|
21022
21067
|
const generateKeystoreAuto = (api, applicationIdentifier) => Effect.gen(function* () {
|
|
21023
21068
|
yield* Console.log("Generating a new Android Keystore...");
|
|
21024
|
-
const passphrase = yield* resolveVaultPassphrase;
|
|
21025
21069
|
return (yield* generateAndUploadKeystore(api, {
|
|
21026
21070
|
keyAlias: "upload",
|
|
21027
21071
|
storePassword: randomKeystoreSecret(),
|
|
21028
21072
|
keyPassword: randomKeystoreSecret(),
|
|
21029
21073
|
commonName: applicationIdentifier,
|
|
21030
|
-
organization: "better-update"
|
|
21031
|
-
...compact({ passphrase })
|
|
21074
|
+
organization: "better-update"
|
|
21032
21075
|
})).id;
|
|
21033
21076
|
});
|
|
21034
21077
|
const generateKeystoreInteractive = (api) => Effect.gen(function* () {
|
|
@@ -21037,15 +21080,13 @@ const generateKeystoreInteractive = (api) => Effect.gen(function* () {
|
|
|
21037
21080
|
const keyPassword = yield* promptPassword("Key password");
|
|
21038
21081
|
const commonName = yield* promptText("Common name (CN)", { placeholder: "Your App" });
|
|
21039
21082
|
const organization = yield* promptText("Organization (O)", { placeholder: "Your Company" });
|
|
21040
|
-
const passphrase = yield* resolveVaultPassphrase;
|
|
21041
21083
|
yield* Console.log("Generating keystore with keytool...");
|
|
21042
21084
|
return (yield* generateAndUploadKeystore(api, {
|
|
21043
21085
|
keyAlias: alias,
|
|
21044
21086
|
storePassword,
|
|
21045
21087
|
keyPassword,
|
|
21046
21088
|
commonName,
|
|
21047
|
-
organization
|
|
21048
|
-
...compact({ passphrase })
|
|
21089
|
+
organization
|
|
21049
21090
|
})).id;
|
|
21050
21091
|
});
|
|
21051
21092
|
const pickExistingKeystore = (api) => Effect.gen(function* () {
|
|
@@ -21068,6 +21109,25 @@ const resolveAndroidAppId = (api, input) => Effect.gen(function* () {
|
|
|
21068
21109
|
})).id;
|
|
21069
21110
|
});
|
|
21070
21111
|
const resolveAndroidKeystoreId = (api, choice) => choice === "generate" ? generateKeystoreInteractive(api) : pickExistingKeystore(api);
|
|
21112
|
+
const bindAndroidKeystore = (api, appId, keystoreId) => Effect.gen(function* () {
|
|
21113
|
+
const existing = yield* api.androidBuildCredentials.list({ path: { applicationIdentifierId: appId } });
|
|
21114
|
+
const target = existing.items.find((group) => group.isDefault) ?? existing.items.at(0);
|
|
21115
|
+
if (target === void 0) {
|
|
21116
|
+
yield* api.androidBuildCredentials.create({
|
|
21117
|
+
path: { applicationIdentifierId: appId },
|
|
21118
|
+
payload: {
|
|
21119
|
+
name: "Default",
|
|
21120
|
+
isDefault: true,
|
|
21121
|
+
androidUploadKeystoreId: keystoreId
|
|
21122
|
+
}
|
|
21123
|
+
});
|
|
21124
|
+
return;
|
|
21125
|
+
}
|
|
21126
|
+
yield* api.androidBuildCredentials.update({
|
|
21127
|
+
path: { id: target.id },
|
|
21128
|
+
payload: { androidUploadKeystoreId: keystoreId }
|
|
21129
|
+
});
|
|
21130
|
+
});
|
|
21071
21131
|
const setupAndroidInteractive = (api, input) => Effect.gen(function* () {
|
|
21072
21132
|
yield* Console.log("");
|
|
21073
21133
|
yield* Console.log(`No Android build credentials configured for ${input.applicationIdentifier}.`);
|
|
@@ -21090,15 +21150,7 @@ const setupAndroidInteractive = (api, input) => Effect.gen(function* () {
|
|
|
21090
21150
|
message: `Build aborted — no keystore bound to ${input.applicationIdentifier}.`,
|
|
21091
21151
|
hint: "Run `better-update credentials generate keystore` or upload via the dashboard."
|
|
21092
21152
|
});
|
|
21093
|
-
|
|
21094
|
-
yield* api.androidBuildCredentials.create({
|
|
21095
|
-
path: { applicationIdentifierId: appId },
|
|
21096
|
-
payload: {
|
|
21097
|
-
name: "Default",
|
|
21098
|
-
isDefault: true,
|
|
21099
|
-
androidUploadKeystoreId: keystoreId
|
|
21100
|
-
}
|
|
21101
|
-
});
|
|
21153
|
+
yield* bindAndroidKeystore(api, appId, yield* choice === "generate" ? generateKeystoreAuto(api, input.applicationIdentifier) : pickExistingKeystore(api));
|
|
21102
21154
|
yield* Console.log("Android build credentials configured.");
|
|
21103
21155
|
});
|
|
21104
21156
|
const ensureAndroidCredentialsAvailable = (api, input) => api.buildCredentials.resolve({
|
|
@@ -22734,7 +22786,8 @@ const warnIfDevClientMissing = (projectRoot) => Effect.gen(function* () {
|
|
|
22734
22786
|
|
|
22735
22787
|
//#endregion
|
|
22736
22788
|
//#region src/lib/env-exporter.ts
|
|
22737
|
-
const
|
|
22789
|
+
const ENVIRONMENT_NAME_PATTERN$1 = /^[a-z][a-z0-9-]*$/u;
|
|
22790
|
+
const coerceEnvironment = (raw) => ENVIRONMENT_NAME_PATTERN$1.test(raw) && raw.length <= 64 ? raw : void 0;
|
|
22738
22791
|
/** Decrypt one sealed env var value, re-checking the sealed metadata against the row. */
|
|
22739
22792
|
const decryptEnvVarValue = (session, item) => openFromDownload({
|
|
22740
22793
|
session,
|
|
@@ -22766,7 +22819,7 @@ const exportDecryptedEnvVars = (api, projectId, environment) => Effect.gen(funct
|
|
|
22766
22819
|
*/
|
|
22767
22820
|
const pullEnvVars = (api, { projectId, environment }) => Effect.gen(function* () {
|
|
22768
22821
|
const validated = coerceEnvironment(environment);
|
|
22769
|
-
if (!validated) return yield* new EnvExportError({ message: `Invalid environment "${environment}"
|
|
22822
|
+
if (!validated) return yield* new EnvExportError({ message: `Invalid environment "${environment}": must be lowercase letters, digits, and hyphens, starting with a letter.` });
|
|
22770
22823
|
const items = yield* exportDecryptedEnvVars(api, projectId, validated);
|
|
22771
22824
|
return Object.fromEntries(items.map((item) => [item.key, item.value]));
|
|
22772
22825
|
});
|
|
@@ -24536,7 +24589,7 @@ const compatibilityMatrixCommand = defineCommand({
|
|
|
24536
24589
|
|
|
24537
24590
|
//#endregion
|
|
24538
24591
|
//#region src/commands/builds/delete.ts
|
|
24539
|
-
const deleteCommand$
|
|
24592
|
+
const deleteCommand$6 = defineCommand({
|
|
24540
24593
|
meta: {
|
|
24541
24594
|
name: "delete",
|
|
24542
24595
|
description: "Delete a build"
|
|
@@ -24682,7 +24735,7 @@ const DISTRIBUTION_OPTIONS$1 = [
|
|
|
24682
24735
|
"play-store",
|
|
24683
24736
|
"direct"
|
|
24684
24737
|
];
|
|
24685
|
-
const listCommand$
|
|
24738
|
+
const listCommand$8 = defineCommand({
|
|
24686
24739
|
meta: {
|
|
24687
24740
|
name: "list",
|
|
24688
24741
|
description: "List builds for the linked project"
|
|
@@ -25340,9 +25393,9 @@ const buildsCommand = defineCommand({
|
|
|
25340
25393
|
description: "Manage builds"
|
|
25341
25394
|
},
|
|
25342
25395
|
subCommands: {
|
|
25343
|
-
list: listCommand$
|
|
25396
|
+
list: listCommand$8,
|
|
25344
25397
|
get: getCommand$2,
|
|
25345
|
-
delete: deleteCommand$
|
|
25398
|
+
delete: deleteCommand$6,
|
|
25346
25399
|
download: downloadCommand$1,
|
|
25347
25400
|
run: runCommand$1,
|
|
25348
25401
|
"install-link": installLinkCommand,
|
|
@@ -25368,7 +25421,7 @@ const resolveNamedResourceId$1 = (params) => resolveNamedResourceId$2(params, (m
|
|
|
25368
25421
|
|
|
25369
25422
|
//#endregion
|
|
25370
25423
|
//#region src/commands/channels/create.ts
|
|
25371
|
-
const createCommand$
|
|
25424
|
+
const createCommand$4 = defineCommand({
|
|
25372
25425
|
meta: {
|
|
25373
25426
|
name: "create",
|
|
25374
25427
|
description: "Create a channel"
|
|
@@ -25413,7 +25466,7 @@ const createCommand$3 = defineCommand({
|
|
|
25413
25466
|
|
|
25414
25467
|
//#endregion
|
|
25415
25468
|
//#region src/commands/channels/delete.ts
|
|
25416
|
-
const deleteCommand$
|
|
25469
|
+
const deleteCommand$5 = defineCommand({
|
|
25417
25470
|
meta: {
|
|
25418
25471
|
name: "delete",
|
|
25419
25472
|
description: "Delete a channel"
|
|
@@ -25482,7 +25535,7 @@ const insightsCommand$1 = defineCommand({
|
|
|
25482
25535
|
|
|
25483
25536
|
//#endregion
|
|
25484
25537
|
//#region src/commands/channels/list.ts
|
|
25485
|
-
const listCommand$
|
|
25538
|
+
const listCommand$7 = defineCommand({
|
|
25486
25539
|
meta: {
|
|
25487
25540
|
name: "list",
|
|
25488
25541
|
description: "List channels for the linked project"
|
|
@@ -25586,7 +25639,7 @@ const completeCommand$1 = defineCommand({
|
|
|
25586
25639
|
|
|
25587
25640
|
//#endregion
|
|
25588
25641
|
//#region src/commands/channels/rollout/create.ts
|
|
25589
|
-
const createCommand$
|
|
25642
|
+
const createCommand$3 = defineCommand({
|
|
25590
25643
|
meta: {
|
|
25591
25644
|
name: "create",
|
|
25592
25645
|
description: "Start a branch rollout on a channel"
|
|
@@ -25706,7 +25759,7 @@ const rolloutCommand$1 = defineCommand({
|
|
|
25706
25759
|
description: "Manage channel branch rollouts"
|
|
25707
25760
|
},
|
|
25708
25761
|
subCommands: {
|
|
25709
|
-
create: createCommand$
|
|
25762
|
+
create: createCommand$3,
|
|
25710
25763
|
update: updateCommand$3,
|
|
25711
25764
|
complete: completeCommand$1,
|
|
25712
25765
|
revert: revertCommand$2
|
|
@@ -25818,13 +25871,13 @@ const channelsCommand = defineCommand({
|
|
|
25818
25871
|
description: "Manage channels"
|
|
25819
25872
|
},
|
|
25820
25873
|
subCommands: {
|
|
25821
|
-
list: listCommand$
|
|
25874
|
+
list: listCommand$7,
|
|
25822
25875
|
view: viewCommand$2,
|
|
25823
|
-
create: createCommand$
|
|
25876
|
+
create: createCommand$4,
|
|
25824
25877
|
update: updateCommand$2,
|
|
25825
25878
|
pause: pauseCommand,
|
|
25826
25879
|
resume: resumeCommand,
|
|
25827
|
-
delete: deleteCommand$
|
|
25880
|
+
delete: deleteCommand$5,
|
|
25828
25881
|
rollout: rolloutCommand$1,
|
|
25829
25882
|
insights: insightsCommand$1
|
|
25830
25883
|
}
|
|
@@ -26004,7 +26057,7 @@ const uploadIosDistributionCertificate = (api, input, bytes) => Effect.gen(funct
|
|
|
26004
26057
|
validUntil: info.expiresAt.toISOString()
|
|
26005
26058
|
};
|
|
26006
26059
|
const envelope = yield* sealForUpload({
|
|
26007
|
-
session: yield*
|
|
26060
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26008
26061
|
credentialType: "distribution-certificate",
|
|
26009
26062
|
metadata,
|
|
26010
26063
|
secret: {
|
|
@@ -26030,7 +26083,7 @@ const uploadIosPushKey = (api, input, bytes) => Effect.gen(function* () {
|
|
|
26030
26083
|
appleTeamIdentifier: input.appleTeamIdentifier
|
|
26031
26084
|
};
|
|
26032
26085
|
const envelope = yield* sealForUpload({
|
|
26033
|
-
session: yield*
|
|
26086
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26034
26087
|
credentialType: "push-key",
|
|
26035
26088
|
metadata,
|
|
26036
26089
|
secret: { p8Pem: toUtf8(bytes) }
|
|
@@ -26055,7 +26108,7 @@ const uploadIosAscApiKey = (api, input, bytes) => Effect.gen(function* () {
|
|
|
26055
26108
|
appleTeamIdentifier: input.appleTeamIdentifier
|
|
26056
26109
|
});
|
|
26057
26110
|
const envelope = yield* sealForUpload({
|
|
26058
|
-
session: yield*
|
|
26111
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26059
26112
|
credentialType: "asc-api-key",
|
|
26060
26113
|
metadata,
|
|
26061
26114
|
secret: { p8Pem: toUtf8(bytes) }
|
|
@@ -26089,7 +26142,7 @@ const uploadAndroidKeystore = (api, input, bytes) => Effect.gen(function* () {
|
|
|
26089
26142
|
keyPassword: input.keyPassword
|
|
26090
26143
|
})).keyAlias };
|
|
26091
26144
|
const envelope = yield* sealForUpload({
|
|
26092
|
-
session: yield*
|
|
26145
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26093
26146
|
credentialType: "keystore",
|
|
26094
26147
|
metadata,
|
|
26095
26148
|
secret: {
|
|
@@ -26117,7 +26170,7 @@ const uploadAndroidGoogleServiceAccountKey = (api, input, bytes) => Effect.gen(f
|
|
|
26117
26170
|
googleProjectId: parsed.googleProjectId
|
|
26118
26171
|
};
|
|
26119
26172
|
const envelope = yield* sealForUpload({
|
|
26120
|
-
session: yield*
|
|
26173
|
+
session: yield* openVaultSessionInteractive(api),
|
|
26121
26174
|
credentialType: "google-service-account-key",
|
|
26122
26175
|
metadata,
|
|
26123
26176
|
secret: { json }
|
|
@@ -26146,10 +26199,7 @@ const uploadCredential = (api, input) => Effect.gen(function* () {
|
|
|
26146
26199
|
const hasKey = (candidate) => Object.hasOwn(uploadHandlers, candidate);
|
|
26147
26200
|
const handler = hasKey(key) ? uploadHandlers[key] : void 0;
|
|
26148
26201
|
if (!handler) return yield* new CredentialValidationError({ message: `Unsupported credential combination: platform=${input.platform} type=${input.type}` });
|
|
26149
|
-
return yield* handler(api, input
|
|
26150
|
-
...input,
|
|
26151
|
-
...compact({ passphrase: yield* resolveVaultPassphrase })
|
|
26152
|
-
}, bytes);
|
|
26202
|
+
return yield* handler(api, input, bytes);
|
|
26153
26203
|
});
|
|
26154
26204
|
const deleteCredential = (api, input) => {
|
|
26155
26205
|
const path = { id: input.id };
|
|
@@ -27140,10 +27190,14 @@ const runCredentialsManager = Effect.gen(function* () {
|
|
|
27140
27190
|
* one, re-wrap the new vault key to each recipient, then submit the rotation
|
|
27141
27191
|
* atomically (the server CAS-guards on the current version and requires a
|
|
27142
27192
|
* recovery recipient in the set). Drops every recipient not in `recipients`.
|
|
27193
|
+
*
|
|
27194
|
+
* Unlocks via the cache-aware path (reusing a live `credentials unlock` session),
|
|
27195
|
+
* then drops that cached key once the re-key lands — it is now stale, so the next
|
|
27196
|
+
* operation must re-unlock at the new version.
|
|
27143
27197
|
*/
|
|
27144
27198
|
const rotateVaultTo = (args) => Effect.gen(function* () {
|
|
27145
27199
|
const orgId = yield* getActiveOrgId(args.api);
|
|
27146
|
-
const current = yield*
|
|
27200
|
+
const current = yield* unlockVaultKeyInteractive(args.api);
|
|
27147
27201
|
const newVaultKey = generateVaultKey();
|
|
27148
27202
|
const newVersion = current.vaultVersion + 1;
|
|
27149
27203
|
const { deks } = yield* args.api.orgVault.listCredentialDeks();
|
|
@@ -27181,11 +27235,13 @@ const rotateVaultTo = (args) => Effect.gen(function* () {
|
|
|
27181
27235
|
recipient: recipient.publicKey
|
|
27182
27236
|
}))
|
|
27183
27237
|
})), { concurrency: "unbounded" });
|
|
27184
|
-
|
|
27238
|
+
const rotated = yield* args.api.orgVault.rotate({ payload: {
|
|
27185
27239
|
fromVersion: current.vaultVersion,
|
|
27186
27240
|
recipientWraps,
|
|
27187
27241
|
credentialDeks
|
|
27188
27242
|
} });
|
|
27243
|
+
yield* forgetCachedVaultKey;
|
|
27244
|
+
return rotated;
|
|
27189
27245
|
});
|
|
27190
27246
|
/** The encryption keys currently holding the vault key, joined with their public keys. */
|
|
27191
27247
|
const currentRecipients = (api) => Effect.gen(function* () {
|
|
@@ -27239,7 +27295,7 @@ const toRecipientView = (userEncryptionKeyId, key) => ({
|
|
|
27239
27295
|
fingerprint: key?.fingerprint
|
|
27240
27296
|
})
|
|
27241
27297
|
});
|
|
27242
|
-
const listCommand$
|
|
27298
|
+
const listCommand$6 = defineCommand({
|
|
27243
27299
|
meta: {
|
|
27244
27300
|
name: "list",
|
|
27245
27301
|
description: "List recipients that currently hold the org vault key"
|
|
@@ -27320,7 +27376,6 @@ const rotateCommand = defineCommand({
|
|
|
27320
27376
|
yield* confirmRecipients(recipients, args.yes === true);
|
|
27321
27377
|
const rotated = yield* rotateVaultTo({
|
|
27322
27378
|
api,
|
|
27323
|
-
passphrase: yield* resolveVaultPassphrase,
|
|
27324
27379
|
recipients: recipients.map(toRotationRecipient)
|
|
27325
27380
|
});
|
|
27326
27381
|
yield* printHuman(`Rotated the vault to version ${String(rotated.vaultVersion)} (${String(recipients.length)} recipients).`);
|
|
@@ -27356,7 +27411,6 @@ const revokeCommand$1 = defineCommand({
|
|
|
27356
27411
|
yield* confirmRecipients(surviving, args.yes === true);
|
|
27357
27412
|
const rotated = yield* rotateVaultTo({
|
|
27358
27413
|
api,
|
|
27359
|
-
passphrase: yield* resolveVaultPassphrase,
|
|
27360
27414
|
recipients: surviving.map(toRotationRecipient)
|
|
27361
27415
|
});
|
|
27362
27416
|
yield* printHuman(`Revoked ${target.label} and rotated the vault to version ${String(rotated.vaultVersion)}.`);
|
|
@@ -27442,7 +27496,6 @@ const recoveryCommand = defineCommand({
|
|
|
27442
27496
|
yield* confirmRecipients(surviving, args.yes === true);
|
|
27443
27497
|
const rotated = yield* rotateVaultTo({
|
|
27444
27498
|
api,
|
|
27445
|
-
passphrase: yield* resolveVaultPassphrase,
|
|
27446
27499
|
recipients: [...surviving.map(toRotationRecipient), {
|
|
27447
27500
|
userEncryptionKeyId: registered.id,
|
|
27448
27501
|
publicKey: newRecovery.publicKey
|
|
@@ -27466,7 +27519,7 @@ const accessCommand = defineCommand({
|
|
|
27466
27519
|
description: "Inspect, grant, rotate, revoke, and recover access to the org credential vault"
|
|
27467
27520
|
},
|
|
27468
27521
|
subCommands: {
|
|
27469
|
-
list: listCommand$
|
|
27522
|
+
list: listCommand$6,
|
|
27470
27523
|
grant: grantCommand,
|
|
27471
27524
|
rotate: rotateCommand,
|
|
27472
27525
|
revoke: revokeCommand$1,
|
|
@@ -27675,7 +27728,7 @@ const CREDENTIAL_TYPES$3 = [
|
|
|
27675
27728
|
"keystore",
|
|
27676
27729
|
"google-service-account-key"
|
|
27677
27730
|
];
|
|
27678
|
-
const deleteCommand$
|
|
27731
|
+
const deleteCommand$4 = defineCommand({
|
|
27679
27732
|
meta: {
|
|
27680
27733
|
name: "delete",
|
|
27681
27734
|
description: "Delete a credential"
|
|
@@ -27717,7 +27770,7 @@ const deleteCommand$3 = defineCommand({
|
|
|
27717
27770
|
//#region src/commands/credentials/device.ts
|
|
27718
27771
|
/** Self-linking is for your own device keys; recovery/machine keys go through `access grant`. */
|
|
27719
27772
|
const requireDeviceKind = (target) => target.kind === "device" ? Effect.void : new IdentityError({ message: `Key ${target.id} is a ${target.kind} key, not a device. Use \`better-update credentials access grant\` for recovery/machine keys.` });
|
|
27720
|
-
const listCommand$
|
|
27773
|
+
const listCommand$5 = defineCommand({
|
|
27721
27774
|
meta: {
|
|
27722
27775
|
name: "list",
|
|
27723
27776
|
description: "List your registered device keys (the active one is marked)"
|
|
@@ -27775,7 +27828,7 @@ const deviceCommand = defineCommand({
|
|
|
27775
27828
|
description: "Manage your vault device keys"
|
|
27776
27829
|
},
|
|
27777
27830
|
subCommands: {
|
|
27778
|
-
list: listCommand$
|
|
27831
|
+
list: listCommand$5,
|
|
27779
27832
|
link: linkCommand
|
|
27780
27833
|
},
|
|
27781
27834
|
default: "list"
|
|
@@ -28430,7 +28483,7 @@ const printRecipient = (key) => printKeyValue([
|
|
|
28430
28483
|
["Recipient (public key)", key.publicKey],
|
|
28431
28484
|
["Fingerprint", key.fingerprint]
|
|
28432
28485
|
]);
|
|
28433
|
-
const createCommand$
|
|
28486
|
+
const createCommand$2 = defineCommand({
|
|
28434
28487
|
meta: {
|
|
28435
28488
|
name: "create",
|
|
28436
28489
|
description: "Create this device's encryption identity and register it as a recipient"
|
|
@@ -28533,7 +28586,7 @@ const identityCommand = defineCommand({
|
|
|
28533
28586
|
description: "Manage this device's end-to-end encryption identity"
|
|
28534
28587
|
},
|
|
28535
28588
|
subCommands: {
|
|
28536
|
-
create: createCommand$
|
|
28589
|
+
create: createCommand$2,
|
|
28537
28590
|
init: initCommand$1,
|
|
28538
28591
|
register: registerCommand,
|
|
28539
28592
|
show: showCommand
|
|
@@ -28543,7 +28596,7 @@ const identityCommand = defineCommand({
|
|
|
28543
28596
|
|
|
28544
28597
|
//#endregion
|
|
28545
28598
|
//#region src/commands/credentials/list.ts
|
|
28546
|
-
const listCommand$
|
|
28599
|
+
const listCommand$4 = defineCommand({
|
|
28547
28600
|
meta: {
|
|
28548
28601
|
name: "list",
|
|
28549
28602
|
description: "List credentials across platforms"
|
|
@@ -29745,14 +29798,14 @@ const credentialsCommand = defineCommand({
|
|
|
29745
29798
|
unlock: unlockCommand,
|
|
29746
29799
|
lock: lockCommand,
|
|
29747
29800
|
status: statusCommand$1,
|
|
29748
|
-
list: listCommand$
|
|
29801
|
+
list: listCommand$4,
|
|
29749
29802
|
view: viewCommand$1,
|
|
29750
29803
|
download: downloadCommand,
|
|
29751
29804
|
upload: uploadCommand,
|
|
29752
29805
|
"upload-asc-key": uploadAscKeyCommand,
|
|
29753
29806
|
generate: generateCommand$1,
|
|
29754
29807
|
"regenerate-profile": regenerateProfileCommand,
|
|
29755
|
-
delete: deleteCommand$
|
|
29808
|
+
delete: deleteCommand$4,
|
|
29756
29809
|
remove: removeCommand,
|
|
29757
29810
|
revoke: revokeCommand,
|
|
29758
29811
|
configure: configureCommand$1,
|
|
@@ -30252,19 +30305,20 @@ const envErrorExtras = {
|
|
|
30252
30305
|
SystemError: 6,
|
|
30253
30306
|
BadArgument: 6
|
|
30254
30307
|
};
|
|
30255
|
-
const
|
|
30308
|
+
const ENVIRONMENT_NAME_PATTERN = /^[a-z][a-z0-9-]*$/u;
|
|
30309
|
+
const isEnvironmentName = (value) => ENVIRONMENT_NAME_PATTERN.test(value) && value.length <= 64;
|
|
30256
30310
|
const parseEnvironmentsArg = (raw) => Effect.gen(function* () {
|
|
30257
30311
|
const tokens = raw.split(",").map((token) => token.trim()).filter((token) => token.length > 0);
|
|
30258
|
-
if (tokens.length === 0) return yield* new InvalidArgumentError({ message: "Provide at least one environment (development, preview, production)." });
|
|
30312
|
+
if (tokens.length === 0) return yield* new InvalidArgumentError({ message: "Provide at least one environment (e.g. development, preview, production)." });
|
|
30259
30313
|
const seen = /* @__PURE__ */ new Set();
|
|
30260
30314
|
yield* Effect.forEach(tokens, (token) => Effect.gen(function* () {
|
|
30261
|
-
if (!isEnvironmentName(token)) return yield* new InvalidArgumentError({ message: `Invalid environment "${token}"
|
|
30315
|
+
if (!isEnvironmentName(token)) return yield* new InvalidArgumentError({ message: `Invalid environment "${token}": must be lowercase letters, digits, and hyphens, starting with a letter.` });
|
|
30262
30316
|
seen.add(token);
|
|
30263
30317
|
}), { discard: true });
|
|
30264
30318
|
return [...seen];
|
|
30265
30319
|
});
|
|
30266
30320
|
const parseSingleEnvironmentArg = (raw) => Effect.gen(function* () {
|
|
30267
|
-
if (!isEnvironmentName(raw)) return yield* new InvalidArgumentError({ message: `Invalid environment "${raw}"
|
|
30321
|
+
if (!isEnvironmentName(raw)) return yield* new InvalidArgumentError({ message: `Invalid environment "${raw}": must be lowercase letters, digits, and hyphens, starting with a letter.` });
|
|
30268
30322
|
return raw;
|
|
30269
30323
|
});
|
|
30270
30324
|
const formatEnvironments = (environments) => [...environments].toSorted((left, right) => left.localeCompare(right)).join(",");
|
|
@@ -30303,7 +30357,7 @@ const findProjectEnvVar = (api, projectId, key, environment) => Effect.gen(funct
|
|
|
30303
30357
|
|
|
30304
30358
|
//#endregion
|
|
30305
30359
|
//#region src/commands/env/delete.ts
|
|
30306
|
-
const deleteCommand$
|
|
30360
|
+
const deleteCommand$3 = defineCommand({
|
|
30307
30361
|
meta: {
|
|
30308
30362
|
name: "delete",
|
|
30309
30363
|
description: "Delete a project env var (one environment, or every environment by default)"
|
|
@@ -30573,7 +30627,7 @@ const importCommand = defineCommand({
|
|
|
30573
30627
|
|
|
30574
30628
|
//#endregion
|
|
30575
30629
|
//#region src/commands/env/list.ts
|
|
30576
|
-
const listCommand$
|
|
30630
|
+
const listCommand$3 = defineCommand({
|
|
30577
30631
|
meta: {
|
|
30578
30632
|
name: "list",
|
|
30579
30633
|
description: "List environment variable metadata. Values are end-to-end encrypted — read them with `env pull`, `env export`, or `env get`."
|
|
@@ -30920,11 +30974,11 @@ const envCommand = defineCommand({
|
|
|
30920
30974
|
description: "Manage environment variables"
|
|
30921
30975
|
},
|
|
30922
30976
|
subCommands: {
|
|
30923
|
-
list: listCommand$
|
|
30977
|
+
list: listCommand$3,
|
|
30924
30978
|
get: getCommand$1,
|
|
30925
30979
|
set: setCommand$1,
|
|
30926
30980
|
update: updateCommand$1,
|
|
30927
|
-
delete: deleteCommand$
|
|
30981
|
+
delete: deleteCommand$3,
|
|
30928
30982
|
history: historyCommand,
|
|
30929
30983
|
rollback: rollbackCommand$1,
|
|
30930
30984
|
import: importCommand,
|
|
@@ -30935,6 +30989,93 @@ const envCommand = defineCommand({
|
|
|
30935
30989
|
}
|
|
30936
30990
|
});
|
|
30937
30991
|
|
|
30992
|
+
//#endregion
|
|
30993
|
+
//#region src/commands/environments.ts
|
|
30994
|
+
const listCommand$2 = defineCommand({
|
|
30995
|
+
meta: {
|
|
30996
|
+
name: "list",
|
|
30997
|
+
description: "List the organization's environments"
|
|
30998
|
+
},
|
|
30999
|
+
run: async () => runEffect(Effect.gen(function* () {
|
|
31000
|
+
const { items } = yield* (yield* apiClient).environments.list();
|
|
31001
|
+
yield* printList(["Name", "Built-in"], items.map((environment) => [environment.name, environment.isBuiltin ? "yes" : "no"]), "No environments found.");
|
|
31002
|
+
return items;
|
|
31003
|
+
}), { json: "value" })
|
|
31004
|
+
});
|
|
31005
|
+
const createCommand$1 = defineCommand({
|
|
31006
|
+
meta: {
|
|
31007
|
+
name: "create",
|
|
31008
|
+
description: "Create a user-defined environment"
|
|
31009
|
+
},
|
|
31010
|
+
args: { name: {
|
|
31011
|
+
type: "positional",
|
|
31012
|
+
required: true,
|
|
31013
|
+
description: "Environment name (lowercase letters, digits, hyphens)"
|
|
31014
|
+
} },
|
|
31015
|
+
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
31016
|
+
const environment = yield* (yield* apiClient).environments.create({ payload: { name: args.name } });
|
|
31017
|
+
yield* printKeyValue([["Name", environment.name], ["Created", environment.createdAt]]);
|
|
31018
|
+
return environment;
|
|
31019
|
+
}), { json: "value" })
|
|
31020
|
+
});
|
|
31021
|
+
const renameCommand$1 = defineCommand({
|
|
31022
|
+
meta: {
|
|
31023
|
+
name: "rename",
|
|
31024
|
+
description: "Rename a user-defined environment"
|
|
31025
|
+
},
|
|
31026
|
+
args: {
|
|
31027
|
+
name: {
|
|
31028
|
+
type: "positional",
|
|
31029
|
+
required: true,
|
|
31030
|
+
description: "Current environment name"
|
|
31031
|
+
},
|
|
31032
|
+
to: {
|
|
31033
|
+
type: "string",
|
|
31034
|
+
required: true,
|
|
31035
|
+
description: "New environment name"
|
|
31036
|
+
}
|
|
31037
|
+
},
|
|
31038
|
+
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
31039
|
+
const environment = yield* (yield* apiClient).environments.rename({
|
|
31040
|
+
path: { name: args.name },
|
|
31041
|
+
payload: { name: args.to }
|
|
31042
|
+
});
|
|
31043
|
+
yield* printHuman(`Environment renamed to "${environment.name}".`);
|
|
31044
|
+
return environment;
|
|
31045
|
+
}), { json: "value" })
|
|
31046
|
+
});
|
|
31047
|
+
const deleteCommand$2 = defineCommand({
|
|
31048
|
+
meta: {
|
|
31049
|
+
name: "delete",
|
|
31050
|
+
description: "Delete a user-defined environment"
|
|
31051
|
+
},
|
|
31052
|
+
args: { name: {
|
|
31053
|
+
type: "positional",
|
|
31054
|
+
required: true,
|
|
31055
|
+
description: "Environment name"
|
|
31056
|
+
} },
|
|
31057
|
+
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
31058
|
+
yield* (yield* apiClient).environments.delete({ path: { name: args.name } });
|
|
31059
|
+
yield* printHuman(`Environment "${args.name}" deleted.`);
|
|
31060
|
+
return {
|
|
31061
|
+
name: args.name,
|
|
31062
|
+
deleted: true
|
|
31063
|
+
};
|
|
31064
|
+
}), { json: "value" })
|
|
31065
|
+
});
|
|
31066
|
+
const environmentsCommand = defineCommand({
|
|
31067
|
+
meta: {
|
|
31068
|
+
name: "environments",
|
|
31069
|
+
description: "Manage organization environments"
|
|
31070
|
+
},
|
|
31071
|
+
subCommands: {
|
|
31072
|
+
list: listCommand$2,
|
|
31073
|
+
create: createCommand$1,
|
|
31074
|
+
rename: renameCommand$1,
|
|
31075
|
+
delete: deleteCommand$2
|
|
31076
|
+
}
|
|
31077
|
+
});
|
|
31078
|
+
|
|
30938
31079
|
//#endregion
|
|
30939
31080
|
//#region src/commands/fingerprint/compare.ts
|
|
30940
31081
|
/**
|
|
@@ -35468,6 +35609,7 @@ const commandRegistry = {
|
|
|
35468
35609
|
groups: groupsCommand,
|
|
35469
35610
|
branches: branchesCommand,
|
|
35470
35611
|
channels: channelsCommand,
|
|
35612
|
+
environments: environmentsCommand,
|
|
35471
35613
|
build: buildCommand,
|
|
35472
35614
|
builds: buildsCommand,
|
|
35473
35615
|
credentials: credentialsCommand,
|