@better-update/cli 0.7.1 → 0.8.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 CHANGED
@@ -21,7 +21,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
21
21
 
22
22
  //#endregion
23
23
  //#region package.json
24
- var version = "0.7.1";
24
+ var version = "0.8.0";
25
25
 
26
26
  //#endregion
27
27
  //#region ../../packages/type-guards/src/index.ts
@@ -664,8 +664,20 @@ var Branch = class extends Schema.Class("Branch")({
664
664
  id: Id,
665
665
  projectId: Id,
666
666
  name: Schema.String,
667
- createdAt: DateTimeString
667
+ createdAt: DateTimeString,
668
+ updateCount: Schema.Number
668
669
  }) {};
670
+ const BranchSortColumn = Schema.Literal("name", "createdAt", "updateCount");
671
+ /**
672
+ * Sort param: column name optionally prefixed with `-` for descending.
673
+ * Example: `name` (asc), `-createdAt` (desc).
674
+ */
675
+ const BranchSort = Schema.Union(BranchSortColumn, Schema.TemplateLiteral("-", BranchSortColumn));
676
+ const ListBranchesParams = Schema.Struct({
677
+ projectId: Id,
678
+ ...PaginationParams.fields,
679
+ sort: Schema.optional(BranchSort)
680
+ });
669
681
  const CreateBranchBody = Schema.Struct({
670
682
  projectId: Id,
671
683
  name: Schema.String.pipe(Schema.minLength(1))
@@ -679,10 +691,12 @@ const idParam$8 = HttpApiSchema.param("id", Schema.String);
679
691
  var BranchesGroup = class extends HttpApiGroup.make("branches").add(HttpApiEndpoint.post("create", "/api/branches").setPayload(CreateBranchBody).addSuccess(Branch, { status: 201 }).annotateContext(OpenApi.annotations({
680
692
  title: "Create branch",
681
693
  description: "Create a new branch within a project"
682
- }))).add(HttpApiEndpoint.get("list", "/api/branches").setUrlParams(Schema.Struct({
683
- projectId: Id,
684
- ...CursorPaginationParams.fields
685
- })).addSuccess(cursorPageResult(Branch)).annotateContext(OpenApi.annotations({
694
+ }))).add(HttpApiEndpoint.get("list", "/api/branches").setUrlParams(ListBranchesParams).addSuccess(Schema.Struct({
695
+ items: Schema.Array(Branch),
696
+ total: Schema.Number,
697
+ page: Schema.Number,
698
+ limit: Schema.Number
699
+ })).annotateContext(OpenApi.annotations({
686
700
  title: "List branches",
687
701
  description: "List all branches for a project"
688
702
  }))).add(HttpApiEndpoint.patch("rename")`/api/branches/${idParam$8}`.setPayload(UpdateBranchBody).addSuccess(Branch).addError(Conflict).annotateContext(OpenApi.annotations({
@@ -829,6 +843,21 @@ const CreateBuildBody = Schema.Union(Schema.Struct({
829
843
  distribution: Schema.Literal("direct"),
830
844
  artifactFormat: Schema.Literal("apk")
831
845
  }));
846
+ const BuildSortColumn = Schema.Literal("createdAt", "platform", "distribution", "runtimeVersion", "appVersion");
847
+ /**
848
+ * Sort param: column name optionally prefixed with `-` for descending.
849
+ * Example: `runtimeVersion` (asc), `-createdAt` (desc).
850
+ */
851
+ const BuildSort = Schema.Union(BuildSortColumn, Schema.TemplateLiteral("-", BuildSortColumn));
852
+ const ListBuildsParams = Schema.Struct({
853
+ projectId: Id,
854
+ platform: Schema.optional(Platform),
855
+ profile: Schema.optional(Schema.String),
856
+ runtimeVersion: Schema.optional(Schema.String),
857
+ distribution: Schema.optional(Distribution),
858
+ ...PaginationParams.fields,
859
+ sort: Schema.optional(BuildSort)
860
+ });
832
861
  const CompleteBuildBody = Schema.Struct({
833
862
  sha256: Sha256Hex,
834
863
  byteSize: Schema.Number.pipe(Schema.nonNegative())
@@ -892,13 +921,12 @@ var BuildsGroup = class extends HttpApiGroup.make("builds").add(HttpApiEndpoint.
892
921
  }))).add(HttpApiEndpoint.post("complete")`/api/builds/${idParam$7}/complete`.setPayload(CompleteBuildBody).addSuccess(BuildWithArtifact).addError(Conflict).annotateContext(OpenApi.annotations({
893
922
  title: "Complete build",
894
923
  description: "Finalize a build after artifact upload"
895
- }))).add(HttpApiEndpoint.get("list", "/api/builds").setUrlParams(Schema.Struct({
896
- projectId: Id,
897
- platform: Schema.optional(Platform),
898
- profile: Schema.optional(Schema.String),
899
- runtimeVersion: Schema.optional(Schema.String),
900
- ...CursorPaginationParams.fields
901
- })).addSuccess(cursorPageResult(BuildWithArtifact)).annotateContext(OpenApi.annotations({
924
+ }))).add(HttpApiEndpoint.get("list", "/api/builds").setUrlParams(ListBuildsParams).addSuccess(Schema.Struct({
925
+ items: Schema.Array(BuildWithArtifact),
926
+ total: Schema.Number,
927
+ page: Schema.Number,
928
+ limit: Schema.Number
929
+ })).annotateContext(OpenApi.annotations({
902
930
  title: "List builds",
903
931
  description: "List builds for a project with optional filters"
904
932
  }))).add(HttpApiEndpoint.get("compatibilityMatrix", "/api/builds/compatibility-matrix").setUrlParams(Schema.Struct({ projectId: Id })).addSuccess(BuildCompatibilityMatrixResult).annotateContext(OpenApi.annotations({
@@ -930,6 +958,17 @@ var Channel = class extends Schema.Class("Channel")({
930
958
  isPaused: Schema.Boolean,
931
959
  createdAt: DateTimeString
932
960
  }) {};
961
+ const ChannelSortColumn = Schema.Literal("name", "createdAt");
962
+ /**
963
+ * Sort param: column name optionally prefixed with `-` for descending.
964
+ * Example: `name` (asc), `-createdAt` (desc).
965
+ */
966
+ const ChannelSort = Schema.Union(ChannelSortColumn, Schema.TemplateLiteral("-", ChannelSortColumn));
967
+ const ListChannelsParams = Schema.Struct({
968
+ projectId: Id,
969
+ ...PaginationParams.fields,
970
+ sort: Schema.optional(ChannelSort)
971
+ });
933
972
  const CreateChannelBody = Schema.Struct({
934
973
  projectId: Id,
935
974
  name: Schema.String.pipe(Schema.minLength(1)),
@@ -951,10 +990,12 @@ var ChannelsGroup = class extends HttpApiGroup.make("channels").add(HttpApiEndpo
951
990
  }))).add(HttpApiEndpoint.patch("update")`/api/channels/${idParam$6}`.setPayload(UpdateChannelBody).addSuccess(Channel).annotateContext(OpenApi.annotations({
952
991
  title: "Update channel",
953
992
  description: "Relink channel to a different branch"
954
- }))).add(HttpApiEndpoint.get("list", "/api/channels").setUrlParams(Schema.Struct({
955
- projectId: Id,
956
- ...CursorPaginationParams.fields
957
- })).addSuccess(cursorPageResult(Channel)).annotateContext(OpenApi.annotations({
993
+ }))).add(HttpApiEndpoint.get("list", "/api/channels").setUrlParams(ListChannelsParams).addSuccess(Schema.Struct({
994
+ items: Schema.Array(Channel),
995
+ total: Schema.Number,
996
+ page: Schema.Number,
997
+ limit: Schema.Number
998
+ })).annotateContext(OpenApi.annotations({
958
999
  title: "List channels",
959
1000
  description: "List all channels for a project"
960
1001
  }))).add(HttpApiEndpoint.post("pause")`/api/channels/${idParam$6}/pause`.addSuccess(Channel).annotateContext(OpenApi.annotations({
@@ -1014,11 +1055,18 @@ const UpdateDeviceBody = Schema.Struct({
1014
1055
  appleTeamId: Schema.optional(Schema.NullOr(Id))
1015
1056
  });
1016
1057
  const DeleteDeviceResult = Schema.Struct({ deleted: Schema.Number });
1058
+ const DeviceSortColumn = Schema.Literal("name", "createdAt", "deviceClass");
1059
+ /**
1060
+ * Sort param: column name optionally prefixed with `-` for descending.
1061
+ * Example: `name` (asc), `-createdAt` (desc).
1062
+ */
1063
+ const DeviceSort = Schema.Union(DeviceSortColumn, Schema.TemplateLiteral("-", DeviceSortColumn));
1017
1064
  const ListDevicesParams = Schema.Struct({
1018
- ...CursorPaginationParams.fields,
1065
+ ...PaginationParams.fields,
1019
1066
  deviceClass: Schema.optional(DeviceClass),
1020
1067
  appleTeamId: Schema.optional(Id),
1021
- query: Schema.optional(Schema.String)
1068
+ query: Schema.optional(Schema.String),
1069
+ sort: Schema.optional(DeviceSort)
1022
1070
  });
1023
1071
  var DeviceRegistrationRequest = class extends Schema.Class("DeviceRegistrationRequest")({
1024
1072
  id: Id,
@@ -1049,7 +1097,12 @@ const idParam$5 = HttpApiSchema.param("id", Schema.String);
1049
1097
  var DevicesGroup = class extends HttpApiGroup.make("devices").add(HttpApiEndpoint.post("register", "/api/devices").setPayload(RegisterDeviceBody).addSuccess(Device, { status: 201 }).annotateContext(OpenApi.annotations({
1050
1098
  title: "Register device",
1051
1099
  description: "Register an Apple device UDID in the caller's active organization"
1052
- }))).add(HttpApiEndpoint.get("list", "/api/devices").setUrlParams(ListDevicesParams).addSuccess(cursorPageResult(Device)).annotateContext(OpenApi.annotations({
1100
+ }))).add(HttpApiEndpoint.get("list", "/api/devices").setUrlParams(ListDevicesParams).addSuccess(Schema.Struct({
1101
+ items: Schema.Array(Device),
1102
+ total: Schema.Number,
1103
+ page: Schema.Number,
1104
+ limit: Schema.Number
1105
+ })).annotateContext(OpenApi.annotations({
1053
1106
  title: "List devices",
1054
1107
  description: "List registered Apple devices in the caller's active organization"
1055
1108
  }))).add(HttpApiEndpoint.get("get")`/api/devices/${idParam$5}`.addSuccess(Device).annotateContext(OpenApi.annotations({
@@ -1256,7 +1309,12 @@ var Project = class extends Schema.Class("Project")({
1256
1309
  channelCount: Schema.Number,
1257
1310
  updateCount: Schema.Number
1258
1311
  }) {};
1259
- const ProjectSort = Schema.Literal("lastActivityAt", "name");
1312
+ const ProjectSortColumn = Schema.Literal("lastActivityAt", "name", "createdAt", "branchCount", "channelCount", "updateCount");
1313
+ /**
1314
+ * Sort param: column name optionally prefixed with `-` for descending.
1315
+ * Example: `name` (asc), `-lastActivityAt` (desc).
1316
+ */
1317
+ const ProjectSort = Schema.Union(ProjectSortColumn, Schema.TemplateLiteral("-", ProjectSortColumn));
1260
1318
  const ListProjectsParams = Schema.Struct({
1261
1319
  ...PaginationParams.fields,
1262
1320
  query: Schema.optional(Schema.String),
@@ -1320,6 +1378,19 @@ var Update = class extends Schema.Class("Update")({
1320
1378
  directiveBody: Schema.NullOr(Schema.String),
1321
1379
  createdAt: DateTimeString
1322
1380
  }) {};
1381
+ const UpdateSortColumn = Schema.Literal("createdAt", "runtimeVersion", "platform", "rolloutPercentage");
1382
+ /**
1383
+ * Sort param: column name optionally prefixed with `-` for descending.
1384
+ * Example: `runtimeVersion` (asc), `-createdAt` (desc).
1385
+ */
1386
+ const UpdateSort = Schema.Union(UpdateSortColumn, Schema.TemplateLiteral("-", UpdateSortColumn));
1387
+ const ListUpdatesParams = Schema.Struct({
1388
+ projectId: Id,
1389
+ branchId: Schema.optional(Id),
1390
+ platform: Schema.optional(Platform),
1391
+ ...PaginationParams.fields,
1392
+ sort: Schema.optional(UpdateSort)
1393
+ });
1323
1394
  const AssetRef = Schema.Struct({
1324
1395
  hash: Schema.String,
1325
1396
  key: Schema.String,
@@ -1372,12 +1443,12 @@ const groupIdParam = HttpApiSchema.param("groupId", Schema.String);
1372
1443
  var UpdatesGroup = class extends HttpApiGroup.make("updates").add(HttpApiEndpoint.post("create", "/api/updates").setPayload(CreateUpdateBody).addSuccess(Update, { status: 201 }).addError(Conflict).annotateContext(OpenApi.annotations({
1373
1444
  title: "Create update",
1374
1445
  description: "Publish a new update (manifest + directive) to a branch"
1375
- }))).add(HttpApiEndpoint.get("list", "/api/updates").setUrlParams(Schema.Struct({
1376
- projectId: Id,
1377
- branchId: Schema.optional(Id),
1378
- platform: Schema.optional(Platform),
1379
- ...CursorPaginationParams.fields
1380
- })).addSuccess(cursorPageResult(Update)).annotateContext(OpenApi.annotations({
1446
+ }))).add(HttpApiEndpoint.get("list", "/api/updates").setUrlParams(ListUpdatesParams).addSuccess(Schema.Struct({
1447
+ items: Schema.Array(Update),
1448
+ total: Schema.Number,
1449
+ page: Schema.Number,
1450
+ limit: Schema.Number
1451
+ })).annotateContext(OpenApi.annotations({
1381
1452
  title: "List updates",
1382
1453
  description: "List updates for a project, optionally filtered by branch"
1383
1454
  }))).add(HttpApiEndpoint.del("deleteGroup")`/api/updates/${groupIdParam}`.addSuccess(DeleteUpdateResult).annotateContext(OpenApi.annotations({
@@ -2004,21 +2075,18 @@ const auditLogsCommand = defineCommand({
2004
2075
 
2005
2076
  //#endregion
2006
2077
  //#region src/lib/drain-cursor.ts
2007
- const PAGE_SIZE = 100;
2008
2078
  const MAX_PAGES = 100;
2009
2079
  /**
2010
- * Drain a cursor-paginated list endpoint into a single array. CLI commands
2011
- * that resolve names → IDs (e.g. branch lookup) need the full set, not a
2012
- * page slice.
2080
+ * Drain a page-numbered list endpoint into a single array. Used by CLI
2081
+ * commands that need the full set, not a page slice.
2013
2082
  */
2014
- const drainCursor = (fetchPage) => {
2015
- const loop = (accumulator, cursor, pages) => fetchPage(cursor).pipe(Effect.flatMap((page) => {
2016
- const next = [...accumulator, ...page.items];
2017
- const { nextCursor } = page;
2018
- const reachedLimit = pages + 1 >= MAX_PAGES || next.length >= PAGE_SIZE * MAX_PAGES;
2019
- return nextCursor === null || reachedLimit ? Effect.succeed(next) : loop(next, nextCursor, pages + 1);
2083
+ const drainPages = (fetchPage) => {
2084
+ const loop = (accumulator, page) => fetchPage(page).pipe(Effect.flatMap((response) => {
2085
+ const next = [...accumulator, ...response.items];
2086
+ const fetched = page * response.limit;
2087
+ return page >= MAX_PAGES || next.length >= response.total || fetched >= response.total ? Effect.succeed(next) : loop(next, page + 1);
2020
2088
  }));
2021
- return loop([], void 0, 0);
2089
+ return loop([], 1);
2022
2090
  };
2023
2091
 
2024
2092
  //#endregion
@@ -2031,10 +2099,10 @@ const listCommand$6 = defineCommand({
2031
2099
  run: async () => runEffect(Effect.gen(function* () {
2032
2100
  const projectId = yield* readProjectId;
2033
2101
  const api = yield* apiClient;
2034
- const items = yield* drainCursor((cursor) => api.branches.list({ urlParams: {
2102
+ const items = yield* drainPages((page) => api.branches.list({ urlParams: {
2035
2103
  projectId,
2036
2104
  limit: 100,
2037
- ...cursor ? { cursor } : {}
2105
+ page
2038
2106
  } }));
2039
2107
  if (items.length === 0) {
2040
2108
  yield* Console.log("No branches found.");
@@ -3686,10 +3754,10 @@ const createCommand$2 = defineCommand({
3686
3754
  const projectId = yield* readProjectId;
3687
3755
  const api = yield* apiClient;
3688
3756
  const branchId = yield* resolveNamedResourceId$1({
3689
- items: yield* drainCursor((cursor) => api.branches.list({ urlParams: {
3757
+ items: yield* drainPages((page) => api.branches.list({ urlParams: {
3690
3758
  projectId,
3691
3759
  limit: 100,
3692
- ...cursor ? { cursor } : {}
3760
+ page
3693
3761
  } })),
3694
3762
  kind: "Branch",
3695
3763
  name: args.branch
@@ -3736,14 +3804,14 @@ const listCommand$4 = defineCommand({
3736
3804
  run: async () => runEffect(Effect.gen(function* () {
3737
3805
  const projectId = yield* readProjectId;
3738
3806
  const api = yield* apiClient;
3739
- const [items, branches] = yield* Effect.all([drainCursor((cursor) => api.channels.list({ urlParams: {
3807
+ const [items, branches] = yield* Effect.all([drainPages((page) => api.channels.list({ urlParams: {
3740
3808
  projectId,
3741
3809
  limit: 100,
3742
- ...cursor ? { cursor } : {}
3743
- } })), drainCursor((cursor) => api.branches.list({ urlParams: {
3810
+ page
3811
+ } })), drainPages((page) => api.branches.list({ urlParams: {
3744
3812
  projectId,
3745
3813
  limit: 100,
3746
- ...cursor ? { cursor } : {}
3814
+ page
3747
3815
  } }))]);
3748
3816
  if (items.length === 0) {
3749
3817
  yield* Console.log("No channels found.");
@@ -3851,10 +3919,10 @@ const createCommand$1 = defineCommand({
3851
3919
  const projectId = yield* readProjectId;
3852
3920
  const api = yield* apiClient;
3853
3921
  const newBranchId = yield* resolveNamedResourceId$1({
3854
- items: yield* drainCursor((cursor) => api.branches.list({ urlParams: {
3922
+ items: yield* drainPages((page) => api.branches.list({ urlParams: {
3855
3923
  projectId,
3856
3924
  limit: 100,
3857
- ...cursor ? { cursor } : {}
3925
+ page
3858
3926
  } })),
3859
3927
  kind: "Branch",
3860
3928
  name: args.branch
@@ -3955,10 +4023,10 @@ const updateCommand$1 = defineCommand({
3955
4023
  const projectId = yield* readProjectId;
3956
4024
  const api = yield* apiClient;
3957
4025
  const branchId = yield* resolveNamedResourceId$1({
3958
- items: yield* drainCursor((cursor) => api.branches.list({ urlParams: {
4026
+ items: yield* drainPages((page) => api.branches.list({ urlParams: {
3959
4027
  projectId,
3960
4028
  limit: 100,
3961
- ...cursor ? { cursor } : {}
4029
+ page
3962
4030
  } })),
3963
4031
  kind: "Branch",
3964
4032
  name: args.branch
@@ -5162,8 +5230,8 @@ const statusCommand = defineCommand({
5162
5230
  yield* Console.log("");
5163
5231
  yield* Console.log("Builds");
5164
5232
  yield* Console.log("------");
5165
- const moreSuffix = builds.nextCursor === null ? "" : "+";
5166
- yield* printKeyValue([["Recent", `${String(builds.items.length)}${moreSuffix}`]]);
5233
+ const moreSuffix = builds.items.length < builds.total ? "+" : "";
5234
+ yield* printKeyValue([["Recent", `${String(builds.items.length)}${moreSuffix}`], ["Total", String(builds.total)]]);
5167
5235
  }))
5168
5236
  });
5169
5237
 
@@ -5219,10 +5287,10 @@ const listCommand = defineCommand({
5219
5287
  const limit = yield* parseLimit(args.limit, 20);
5220
5288
  const projectId = yield* readProjectId;
5221
5289
  const api = yield* apiClient;
5222
- const branches = yield* drainCursor((cursor) => api.branches.list({ urlParams: {
5290
+ const branches = yield* drainPages((page) => api.branches.list({ urlParams: {
5223
5291
  projectId,
5224
5292
  limit: 100,
5225
- ...cursor ? { cursor } : {}
5293
+ page
5226
5294
  } }));
5227
5295
  const branchId = args.branch ? yield* resolveNamedResourceId({
5228
5296
  items: branches,