@better-update/cli 0.39.1 → 0.40.0
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 +96 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -35,7 +35,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
35
35
|
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region package.json
|
|
38
|
-
var version = "0.
|
|
38
|
+
var version = "0.40.0";
|
|
39
39
|
|
|
40
40
|
//#endregion
|
|
41
41
|
//#region src/lib/interactive-mode.ts
|
|
@@ -2402,6 +2402,8 @@ var Project = class extends Schema.Class("Project")({
|
|
|
2402
2402
|
slug: Schema.String,
|
|
2403
2403
|
createdAt: DateTimeString,
|
|
2404
2404
|
lastActivityAt: DateTimeString,
|
|
2405
|
+
/** ISO-8601 timestamp the project was archived (read-only); `null` when active. */
|
|
2406
|
+
archivedAt: Schema.NullOr(DateTimeString),
|
|
2405
2407
|
branchCount: Schema.Number,
|
|
2406
2408
|
channelCount: Schema.Number,
|
|
2407
2409
|
updateCount: Schema.Number
|
|
@@ -2411,7 +2413,8 @@ const ProjectSort = sortParam(ProjectSortColumn);
|
|
|
2411
2413
|
const ListProjectsParams = Schema.Struct({
|
|
2412
2414
|
...PaginationParams.fields,
|
|
2413
2415
|
query: Schema.optional(Schema.String),
|
|
2414
|
-
sort: Schema.optional(ProjectSort)
|
|
2416
|
+
sort: Schema.optional(ProjectSort),
|
|
2417
|
+
status: Schema.optional(Schema.Literal("active", "archived", "all"))
|
|
2415
2418
|
});
|
|
2416
2419
|
const CreateProjectBody = Schema.Struct({
|
|
2417
2420
|
name: Schema.String.pipe(Schema.minLength(1)),
|
|
@@ -2441,6 +2444,12 @@ var ProjectsGroup = class extends HttpApiGroup.make("projects").add(HttpApiEndpo
|
|
|
2441
2444
|
}))).add(HttpApiEndpoint.del("delete")`/api/projects/${idParam}`.addSuccess(DeleteProjectResult).annotateContext(OpenApi.annotations({
|
|
2442
2445
|
title: "Delete project",
|
|
2443
2446
|
description: "Delete a project and all its branches, channels, and updates"
|
|
2447
|
+
}))).add(HttpApiEndpoint.post("archive")`/api/projects/${idParam}/archive`.addSuccess(Project).annotateContext(OpenApi.annotations({
|
|
2448
|
+
title: "Archive project",
|
|
2449
|
+
description: "Archive a project: it is hidden from the default project list and becomes read-only (publishes, builds and other writes are blocked) until unarchived. OTA serving to existing devices is unaffected. Reversible."
|
|
2450
|
+
}))).add(HttpApiEndpoint.post("unarchive")`/api/projects/${idParam}/unarchive`.addSuccess(Project).annotateContext(OpenApi.annotations({
|
|
2451
|
+
title: "Unarchive project",
|
|
2452
|
+
description: "Restore an archived project to active, writable state"
|
|
2444
2453
|
}))).addError(NotFound).addError(Conflict).addError(Forbidden).annotateContext(OpenApi.annotations({
|
|
2445
2454
|
title: "Projects",
|
|
2446
2455
|
description: "Project management endpoints"
|
|
@@ -3527,10 +3536,11 @@ const PresignedUploadClientLive = Layer.effect(PresignedUploadClient, Effect.gen
|
|
|
3527
3536
|
const now = Date.now();
|
|
3528
3537
|
const expiryMs = new Date(expiresAt).getTime();
|
|
3529
3538
|
if (Number.isNaN(expiryMs) || now > expiryMs - EXPIRY_SAFETY_MARGIN_MS) return yield* new PresignedUrlExpiredError({ message: `Presigned upload URL expired or too close to expiry (expiresAt=${expiresAt}).` });
|
|
3530
|
-
const
|
|
3539
|
+
const bytes = yield* fileSystem.readFile(filePath).pipe(Effect.mapError((cause) => new UploadFailedError({ message: `Failed to read artifact for upload: ${String(cause)}` })));
|
|
3540
|
+
const request = HttpClientRequest.put(url).pipe(HttpClientRequest.bodyUint8Array(bytes), HttpClientRequest.setHeaders({
|
|
3531
3541
|
"content-length": String(byteSize),
|
|
3532
3542
|
...headers
|
|
3533
|
-
}))
|
|
3543
|
+
}));
|
|
3534
3544
|
const response = yield* client.execute(request).pipe(Effect.mapError((cause) => new UploadFailedError({ message: `HTTP request to presigned URL failed: ${String(cause)}` })));
|
|
3535
3545
|
if (response.status < 200 || response.status >= 300) {
|
|
3536
3546
|
const body = yield* response.text.pipe(Effect.orElseSucceed(() => ""));
|
|
@@ -33573,6 +33583,11 @@ const policiesCommand = defineCommand({
|
|
|
33573
33583
|
|
|
33574
33584
|
//#endregion
|
|
33575
33585
|
//#region src/commands/projects.ts
|
|
33586
|
+
const projectStatus = (archivedAt) => archivedAt === null ? "active" : "archived";
|
|
33587
|
+
const listStatus = (all, archived) => {
|
|
33588
|
+
if (all) return "all";
|
|
33589
|
+
if (archived) return "archived";
|
|
33590
|
+
};
|
|
33576
33591
|
const listCommand$1 = defineCommand({
|
|
33577
33592
|
meta: {
|
|
33578
33593
|
name: "list",
|
|
@@ -33588,6 +33603,14 @@ const listCommand$1 = defineCommand({
|
|
|
33588
33603
|
description: "Sort key: lastActivityAt (default) or name",
|
|
33589
33604
|
default: "lastActivityAt"
|
|
33590
33605
|
},
|
|
33606
|
+
archived: {
|
|
33607
|
+
type: "boolean",
|
|
33608
|
+
description: "List only archived projects"
|
|
33609
|
+
},
|
|
33610
|
+
all: {
|
|
33611
|
+
type: "boolean",
|
|
33612
|
+
description: "List both active and archived projects"
|
|
33613
|
+
},
|
|
33591
33614
|
limit: {
|
|
33592
33615
|
type: "string",
|
|
33593
33616
|
description: "Page size (default 50, max 100)",
|
|
@@ -33604,21 +33627,25 @@ const listCommand$1 = defineCommand({
|
|
|
33604
33627
|
const sort = args.sort === "name" ? "name" : "lastActivityAt";
|
|
33605
33628
|
const page = yield* parseLimit(args.page, 1);
|
|
33606
33629
|
const limit = yield* parseLimit(args.limit, 50);
|
|
33630
|
+
const status = listStatus(args.all, args.archived);
|
|
33607
33631
|
const result = yield* api.projects.list({ urlParams: {
|
|
33608
33632
|
page,
|
|
33609
33633
|
limit,
|
|
33610
33634
|
sort,
|
|
33611
|
-
...args.query ? { query: args.query } : {}
|
|
33635
|
+
...args.query ? { query: args.query } : {},
|
|
33636
|
+
...status ? { status } : {}
|
|
33612
33637
|
} });
|
|
33613
33638
|
yield* printList([
|
|
33614
33639
|
"ID",
|
|
33615
33640
|
"Name",
|
|
33616
33641
|
"Slug",
|
|
33642
|
+
"Status",
|
|
33617
33643
|
"Last activity"
|
|
33618
33644
|
], result.items.map((project) => [
|
|
33619
33645
|
project.id,
|
|
33620
33646
|
project.name,
|
|
33621
33647
|
project.slug,
|
|
33648
|
+
projectStatus(project.archivedAt),
|
|
33622
33649
|
project.lastActivityAt
|
|
33623
33650
|
]), "No projects found.");
|
|
33624
33651
|
yield* printHuman(`Page ${result.page} · ${result.items.length} of ${result.total} project(s)`);
|
|
@@ -33671,6 +33698,7 @@ const getCommand = defineCommand({
|
|
|
33671
33698
|
["ID", project.id],
|
|
33672
33699
|
["Name", project.name],
|
|
33673
33700
|
["Slug", project.slug],
|
|
33701
|
+
["Status", projectStatus(project.archivedAt)],
|
|
33674
33702
|
["Created", project.createdAt]
|
|
33675
33703
|
]);
|
|
33676
33704
|
return project;
|
|
@@ -33702,10 +33730,38 @@ const renameCommand = defineCommand({
|
|
|
33702
33730
|
return project;
|
|
33703
33731
|
}), { json: "value" })
|
|
33704
33732
|
});
|
|
33705
|
-
const
|
|
33733
|
+
const archiveCommand = defineCommand({
|
|
33706
33734
|
meta: {
|
|
33707
|
-
name: "
|
|
33708
|
-
description: "
|
|
33735
|
+
name: "archive",
|
|
33736
|
+
description: "Archive a project (hides it and makes it read-only until unarchived)"
|
|
33737
|
+
},
|
|
33738
|
+
args: {
|
|
33739
|
+
id: {
|
|
33740
|
+
type: "positional",
|
|
33741
|
+
required: true,
|
|
33742
|
+
description: "Project ID"
|
|
33743
|
+
},
|
|
33744
|
+
yes: {
|
|
33745
|
+
type: "boolean",
|
|
33746
|
+
description: "Skip confirmation prompt"
|
|
33747
|
+
}
|
|
33748
|
+
},
|
|
33749
|
+
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
33750
|
+
if (!args.yes) {
|
|
33751
|
+
if (!(yield* promptConfirm(`Archive project ${args.id}? It becomes read-only (no publishes or builds) until unarchived.`, { initialValue: false }))) {
|
|
33752
|
+
yield* printHuman("Cancelled.");
|
|
33753
|
+
return;
|
|
33754
|
+
}
|
|
33755
|
+
}
|
|
33756
|
+
const project = yield* (yield* apiClient).projects.archive({ path: { id: args.id } });
|
|
33757
|
+
yield* printHuman(`Project ${project.name} archived. Unarchive with: projects unarchive ${project.id}`);
|
|
33758
|
+
return project;
|
|
33759
|
+
}), { json: "value" })
|
|
33760
|
+
});
|
|
33761
|
+
const unarchiveCommand = defineCommand({
|
|
33762
|
+
meta: {
|
|
33763
|
+
name: "unarchive",
|
|
33764
|
+
description: "Restore an archived project to active, writable state"
|
|
33709
33765
|
},
|
|
33710
33766
|
args: { id: {
|
|
33711
33767
|
type: "positional",
|
|
@@ -33713,6 +33769,34 @@ const deleteCommand$1 = defineCommand({
|
|
|
33713
33769
|
description: "Project ID"
|
|
33714
33770
|
} },
|
|
33715
33771
|
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
33772
|
+
const project = yield* (yield* apiClient).projects.unarchive({ path: { id: args.id } });
|
|
33773
|
+
yield* printHuman(`Project ${project.name} unarchived. It is writable again.`);
|
|
33774
|
+
return project;
|
|
33775
|
+
}), { json: "value" })
|
|
33776
|
+
});
|
|
33777
|
+
const deleteCommand$1 = defineCommand({
|
|
33778
|
+
meta: {
|
|
33779
|
+
name: "delete",
|
|
33780
|
+
description: "Delete a project and all its branches, channels, and updates"
|
|
33781
|
+
},
|
|
33782
|
+
args: {
|
|
33783
|
+
id: {
|
|
33784
|
+
type: "positional",
|
|
33785
|
+
required: true,
|
|
33786
|
+
description: "Project ID"
|
|
33787
|
+
},
|
|
33788
|
+
yes: {
|
|
33789
|
+
type: "boolean",
|
|
33790
|
+
description: "Skip confirmation prompt"
|
|
33791
|
+
}
|
|
33792
|
+
},
|
|
33793
|
+
run: async ({ args }) => runEffect(Effect.gen(function* () {
|
|
33794
|
+
if (!args.yes) {
|
|
33795
|
+
if (!(yield* promptConfirm(`Delete project ${args.id}? This permanently removes all its branches, channels, and updates.`, { initialValue: false }))) {
|
|
33796
|
+
yield* printHuman("Cancelled.");
|
|
33797
|
+
return;
|
|
33798
|
+
}
|
|
33799
|
+
}
|
|
33716
33800
|
yield* (yield* apiClient).projects.delete({ path: { id: args.id } });
|
|
33717
33801
|
yield* printHuman(`Project ${args.id} deleted.`);
|
|
33718
33802
|
return {
|
|
@@ -33731,6 +33815,8 @@ const projectsCommand = defineCommand({
|
|
|
33731
33815
|
create: createCommand,
|
|
33732
33816
|
get: getCommand,
|
|
33733
33817
|
rename: renameCommand,
|
|
33818
|
+
archive: archiveCommand,
|
|
33819
|
+
unarchive: unarchiveCommand,
|
|
33734
33820
|
delete: deleteCommand$1
|
|
33735
33821
|
}
|
|
33736
33822
|
});
|
|
@@ -35500,6 +35586,7 @@ const gitCreateFields = (git) => ({
|
|
|
35500
35586
|
...compact({ gitCommit: git.commit })
|
|
35501
35587
|
});
|
|
35502
35588
|
const dedupeAssetsByHash = (assets) => uniqBy(assets, (asset) => asset.hash);
|
|
35589
|
+
const dedupeAssetsByKey = (assets) => uniqBy(assets, (asset) => asset.key);
|
|
35503
35590
|
/**
|
|
35504
35591
|
* Record the per-platform fingerprint (matching EAS) so `fingerprint:compare`
|
|
35505
35592
|
* lines up with the per-platform `fingerprint`-policy RTV. Best-effort: the hash
|
|
@@ -35621,7 +35708,7 @@ const publishPlatform = (params) => Effect.gen(function* () {
|
|
|
35621
35708
|
groupId: params.groupId,
|
|
35622
35709
|
metadata: manifestMetadata,
|
|
35623
35710
|
extra: manifestExtra,
|
|
35624
|
-
assets: preparedAssets.map((asset) => ({
|
|
35711
|
+
assets: dedupeAssetsByKey(preparedAssets).map((asset) => ({
|
|
35625
35712
|
hash: asset.hash,
|
|
35626
35713
|
key: asset.key,
|
|
35627
35714
|
isLaunch: asset.isLaunch,
|