open-phiz-cli 0.1.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/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # `open-phiz-cli`
2
+
3
+ Command-line and CI client for Open Phiz developer APIs. Node.js 22.12 or newer is required.
4
+
5
+ ## Configure
6
+
7
+ Create a short-lived Personal Access Token in the Open Platform Dashboard and expose it through the
8
+ environment. The CLI deliberately rejects token and secret command-line arguments so credentials do
9
+ not enter shell history or process listings.
10
+
11
+ ```bash
12
+ export PHIZ_BASE_URL=https://open.example.com
13
+ export PHIZ_TOKEN="$OPEN_PHIZ_CI_TOKEN"
14
+ ```
15
+
16
+ Use `dev_scope.miniApp.read` and `dev_scope.miniAppVersion.read` for list and status commands. Package
17
+ upload additionally requires `dev_scope.miniAppCI`. Lifecycle writes require
18
+ `dev_scope.miniAppVersion.write`. Keep upload and release credentials on separate, short-lived PATs;
19
+ an upload-only token cannot submit, publish, unpublish, or roll back a version.
20
+
21
+ ## Commands
22
+
23
+ ```bash
24
+ phiz mini-app list
25
+ phiz mini-app list --page 2 --page-size 50 --keyword checkout --json
26
+ phiz mini-app status --app-id wx_example --json
27
+ phiz mini-app upload \
28
+ --app-id wx_example \
29
+ --file ./dist/mini-app.zip \
30
+ --version 1.4.0 \
31
+ --remark "CI draft" \
32
+ --wait \
33
+ --json
34
+ phiz mini-app review submit --app-id wx_example --version-id <id> --confirm --wait --json
35
+ phiz mini-app review withdraw --app-id wx_example --version-id <id> --confirm --json
36
+ phiz mini-app publish --app-id wx_example --version-id <id> --confirm --wait --json
37
+ phiz mini-app unpublish --app-id wx_example --version-id <id> --confirm --wait --json
38
+ phiz mini-app rollback-list --app-id wx_example --json
39
+ phiz mini-app rollback --app-id wx_example --version-id <id> --confirm --wait --json
40
+ ```
41
+
42
+ `--json` emits one JSON object and uses a non-zero exit code for failures. Errors include a stable
43
+ code, HTTP status, Request ID when available, and whether the failure is retryable. Response bodies
44
+ and credentials are never included in diagnostic errors.
45
+
46
+ Upload accepts a regular `.zip` file with a ZIP header and a maximum size of 50 MB. The CLI computes
47
+ SHA-256 before any write, and the server verifies the digest both while receiving the file and before
48
+ creating the draft from stored content.
49
+
50
+ The default idempotency key is deterministically derived from app ID, version, and package SHA-256.
51
+ Upload and build use separate derived keys. A retry after a timeout reuses completed server results;
52
+ rerunning the same command also recovers a visible draft only when its version and digest both match.
53
+ The same version with a different or unverifiable digest fails with `VERSION_CONFLICT`. Use
54
+ `--idempotency-key` only when an external CI system needs to supply its own stable recovery key.
55
+
56
+ Idempotent GET, upload, and build requests are retried at most twice. HTTPS is mandatory outside
57
+ localhost unless `--allow-insecure-http` or `PHIZ_ALLOW_INSECURE_HTTP=1` is set for an isolated
58
+ development network. `--wait` polls draft visibility for up to 120 seconds by default; adjust with
59
+ `--wait-timeout` and `--poll-interval`.
60
+
61
+ Every lifecycle write requires `--confirm`, binds the public App ID to the target Version ID, and uses
62
+ a deterministic idempotency key. The CLI queries version status after the write; `--wait` keeps
63
+ polling until the review, draft, online, or offline state is visible. Use `rollback-list` before a
64
+ rollback to select a version that was previously published. `--auto-publish` is accepted only by
65
+ `review submit` and publishes after a successful review decision.
66
+
67
+ ## GitHub Actions
68
+
69
+ The official reusable workflow keeps upload and release credentials separate. Pin both the workflow
70
+ reference and `cli_version` to immutable released versions. Store an upload-only PAT as
71
+ `OPEN_PHIZ_UPLOAD_TOKEN`; add `OPEN_PHIZ_RELEASE_TOKEN` only when the job submits a review.
72
+
73
+ ```yaml
74
+ jobs:
75
+ open_phiz_release:
76
+ uses: phiz-clip/open-phiz/.github/workflows/open-phiz-mini-app-release.yml@v0.1.0
77
+ with:
78
+ base_url: ${{ vars.OPEN_PHIZ_BASE_URL }}
79
+ app_id: ${{ vars.OPEN_PHIZ_APP_ID }}
80
+ package_path: dist/mini-app.zip
81
+ version: 1.4.0
82
+ cli_version: 0.1.0
83
+ submit_review: true
84
+ auto_publish: false
85
+ secrets:
86
+ upload_token: ${{ secrets.OPEN_PHIZ_UPLOAD_TOKEN }}
87
+ release_token: ${{ secrets.OPEN_PHIZ_RELEASE_TOKEN }}
88
+ ```
89
+
90
+ The workflow defaults to draft upload only. It exposes `version_id` as a reusable workflow output
91
+ and safely recovers a matching draft when a previous run stopped after the server accepted it.
92
+
93
+ ## GitLab CI
94
+
95
+ Include the official hidden job from an immutable tag, extend it in the caller pipeline, and set
96
+ `OPEN_PHIZ_UPLOAD_TOKEN` and `OPEN_PHIZ_RELEASE_TOKEN` as masked, protected variables. Omit the
97
+ release token when `OPEN_PHIZ_SUBMIT_REVIEW` remains `false`.
98
+
99
+ ```yaml
100
+ include:
101
+ - remote: https://raw.githubusercontent.com/phiz-clip/open-phiz/v0.1.0/ci/gitlab/open-phiz-mini-app-release.yml
102
+
103
+ open_phiz_release:
104
+ extends: .open-phiz-mini-app-release
105
+ variables:
106
+ PHIZ_BASE_URL: https://open.example.com
107
+ OPEN_PHIZ_APP_ID: wx_example
108
+ OPEN_PHIZ_VERSION: 1.4.0
109
+ OPEN_PHIZ_CLI_VERSION: 0.1.0
110
+ OPEN_PHIZ_SUBMIT_REVIEW: 'true'
111
+ OPEN_PHIZ_AUTO_PUBLISH: 'false'
112
+ ```
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,936 @@
1
+ #!/usr/bin/env node
2
+ import { createHash } from 'crypto';
3
+ import { createReadStream } from 'fs';
4
+ import { lstat, open, readFile } from 'fs/promises';
5
+ import { basename } from 'path';
6
+
7
+ // src/version.ts
8
+ var CLI_VERSION = "0.1.0" ;
9
+
10
+ // src/client.ts
11
+ var DEFAULT_TIMEOUT_MS = 15e3;
12
+ var DEFAULT_RETRY_COUNT = 2;
13
+ var DEFAULT_RETRY_DELAY_MS = 250;
14
+ function isRecord(value) {
15
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
16
+ }
17
+ function normalizeBaseUrl(value, allowInsecureHttp) {
18
+ let url;
19
+ try {
20
+ url = new URL(value);
21
+ } catch {
22
+ throw new TypeError("PHIZ_BASE_URL must be a valid HTTP(S) URL");
23
+ }
24
+ if (!["http:", "https:"].includes(url.protocol)) {
25
+ throw new TypeError("PHIZ_BASE_URL must use HTTP or HTTPS");
26
+ }
27
+ if (url.username || url.password || url.search || url.hash) {
28
+ throw new TypeError(
29
+ "PHIZ_BASE_URL must not contain credentials, query parameters, or a fragment"
30
+ );
31
+ }
32
+ const localHostnames = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
33
+ if (url.protocol === "http:" && !allowInsecureHttp && !localHostnames.has(url.hostname)) {
34
+ throw new TypeError("PHIZ_BASE_URL must use HTTPS outside localhost");
35
+ }
36
+ url.pathname = `${url.pathname.replace(/\/+$/, "")}/`;
37
+ return url;
38
+ }
39
+ function safeMessage(value, token, fallback) {
40
+ const message = typeof value === "string" ? value : isRecord(value) && typeof value.message === "string" ? value.message : "";
41
+ if (!message.trim()) return fallback;
42
+ return message.replaceAll(token, "[REDACTED]");
43
+ }
44
+ function envelopeErrorCode(envelope, status) {
45
+ if (typeof envelope.errcode === "string" && envelope.errcode) return envelope.errcode;
46
+ if (isRecord(envelope.error) && typeof envelope.error.code === "string" && envelope.error.code) {
47
+ return envelope.error.code;
48
+ }
49
+ return `HTTP_${status}`;
50
+ }
51
+ function requestIdFrom(response) {
52
+ return response.headers.get("x-request-id") ?? void 0;
53
+ }
54
+ function wait(ms) {
55
+ return new Promise((resolve) => setTimeout(resolve, ms));
56
+ }
57
+ var PhizCliError = class extends Error {
58
+ code;
59
+ status;
60
+ requestId;
61
+ retryable;
62
+ constructor(message, options) {
63
+ super(message);
64
+ this.name = "PhizCliError";
65
+ this.code = options.code;
66
+ this.status = options.status;
67
+ this.requestId = options.requestId;
68
+ this.retryable = options.retryable ?? false;
69
+ }
70
+ };
71
+ var PhizApiClient = class {
72
+ baseUrl;
73
+ token;
74
+ fetchImpl;
75
+ timeoutMs;
76
+ retryCount;
77
+ retryDelayMs;
78
+ constructor(options) {
79
+ if (!options.token.startsWith("phiz_")) {
80
+ throw new TypeError("PHIZ_TOKEN must be a Personal Access Token beginning with phiz_");
81
+ }
82
+ this.baseUrl = normalizeBaseUrl(options.baseUrl, options.allowInsecureHttp ?? false);
83
+ this.token = options.token;
84
+ this.fetchImpl = options.fetch ?? globalThis.fetch;
85
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
86
+ this.retryCount = options.retryCount ?? DEFAULT_RETRY_COUNT;
87
+ this.retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
88
+ }
89
+ async listMiniApps(input) {
90
+ const params = new URLSearchParams({
91
+ pageNo: String(input.pageNo),
92
+ pageSize: String(input.pageSize)
93
+ });
94
+ if (input.keyword) params.set("keyword", input.keyword);
95
+ if (input.appStatus) params.set("appStatus", input.appStatus);
96
+ return this.request("GET", "dev/mini-apps/list", { params, retry: true });
97
+ }
98
+ async getMiniAppStatus(appId) {
99
+ return this.request("GET", "dev/mini-apps/versions/latest", {
100
+ params: new URLSearchParams({ miniAppId: appId }),
101
+ retry: true
102
+ });
103
+ }
104
+ async listCompiledPackages(appId, pageSize = 100) {
105
+ return this.request("GET", "dev/mini-apps/compiled-package/list", {
106
+ params: new URLSearchParams({ miniAppId: appId, pageNo: "1", pageSize: String(pageSize) }),
107
+ retry: true
108
+ });
109
+ }
110
+ async uploadCompiledPackage(input) {
111
+ return this.request("POST", "dev/mini-apps/compiled-package/upload", {
112
+ retry: true,
113
+ timeoutMs: 12e4,
114
+ headers: {
115
+ "Idempotency-Key": input.idempotencyKey,
116
+ "X-Content-SHA256": input.packageSha256
117
+ },
118
+ body: () => {
119
+ const formData = new FormData();
120
+ const bytes = Uint8Array.from(input.bytes);
121
+ formData.append(
122
+ "file",
123
+ new File([bytes.buffer], input.filename, { type: "application/zip" })
124
+ );
125
+ return { body: formData };
126
+ }
127
+ });
128
+ }
129
+ async buildDraft(input) {
130
+ return this.request("POST", "dev/mini-apps/compiled-package/build", {
131
+ retry: true,
132
+ timeoutMs: 6e4,
133
+ headers: {
134
+ "Content-Type": "application/json",
135
+ "Idempotency-Key": input.idempotencyKey
136
+ },
137
+ body: () => ({
138
+ body: JSON.stringify({
139
+ version: input.version,
140
+ versionRemark: input.remark,
141
+ miniAppId: input.appId,
142
+ filesFromNetdisk: [{ netdiskID: input.netdiskId, name: input.filename }],
143
+ packages: [],
144
+ packageConfig: {},
145
+ packageSha256: input.packageSha256
146
+ })
147
+ })
148
+ });
149
+ }
150
+ async listRollbackVersions(appId, pageNo, pageSize) {
151
+ return this.request("GET", "dev/mini-apps/versions/rollback/list", {
152
+ params: new URLSearchParams({
153
+ miniAppId: appId,
154
+ pageNo: String(pageNo),
155
+ pageSize: String(pageSize)
156
+ }),
157
+ retry: true
158
+ });
159
+ }
160
+ async executeVersionLifecycle(input) {
161
+ const pathByAction = {
162
+ "review-submit": "dev/mini-apps/versions/review/submit",
163
+ "review-withdraw": "dev/mini-apps/versions/review/withdraw",
164
+ publish: "dev/mini-apps/versions/publish",
165
+ unpublish: "dev/mini-apps/versions/unpublish",
166
+ rollback: "dev/mini-apps/versions/rollback"
167
+ };
168
+ const versionField = input.action === "review-submit" ? "miniAppCompiledPackageId" : "miniAppVersionId";
169
+ return this.request("POST", pathByAction[input.action], {
170
+ retry: true,
171
+ headers: {
172
+ "Content-Type": "application/json",
173
+ "Idempotency-Key": input.idempotencyKey
174
+ },
175
+ body: () => ({
176
+ body: JSON.stringify({
177
+ miniAppId: input.appId,
178
+ [versionField]: input.versionId,
179
+ ...input.action === "review-submit" ? { autoPub: input.autoPublish === true } : {}
180
+ })
181
+ })
182
+ });
183
+ }
184
+ async request(method, path, options) {
185
+ const url = new URL(`api/v1/open/${path}`, this.baseUrl);
186
+ if (options.params) url.search = options.params.toString();
187
+ const maximumAttempts = options.retry ? this.retryCount + 1 : 1;
188
+ for (let attempt = 0; attempt < maximumAttempts; attempt += 1) {
189
+ const controller = new AbortController();
190
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? this.timeoutMs);
191
+ try {
192
+ const requestBody = options.body?.();
193
+ const headers = new Headers({
194
+ Accept: "application/json",
195
+ Authorization: `Bearer ${this.token}`,
196
+ "User-Agent": `open-phiz-cli/${CLI_VERSION}`
197
+ });
198
+ new Headers(options.headers).forEach((value, name) => headers.set(name, value));
199
+ new Headers(requestBody?.headers).forEach((value, name) => headers.set(name, value));
200
+ const response = await this.fetchImpl(url, {
201
+ method,
202
+ redirect: "error",
203
+ headers,
204
+ ...requestBody ? { body: requestBody.body } : {},
205
+ signal: controller.signal
206
+ });
207
+ const requestId = requestIdFrom(response);
208
+ let envelope;
209
+ try {
210
+ envelope = await response.json();
211
+ } catch {
212
+ throw new PhizCliError("Open Phiz returned an invalid JSON response", {
213
+ code: "INVALID_RESPONSE",
214
+ status: response.status,
215
+ ...requestId ? { requestId } : {},
216
+ retryable: response.status === 429 || response.status >= 500
217
+ });
218
+ }
219
+ const retryable = response.status === 429 || response.status >= 500 || response.status === 409 && envelopeErrorCode(envelope, response.status) === "IDEMPOTENCY_IN_PROGRESS";
220
+ if (retryable && attempt + 1 < maximumAttempts) {
221
+ await wait(this.retryDelayMs * 2 ** attempt);
222
+ continue;
223
+ }
224
+ if (!response.ok || envelope.errcode !== void 0 && envelope.errcode !== "OK") {
225
+ const code = envelopeErrorCode(envelope, response.status);
226
+ throw new PhizCliError(
227
+ safeMessage(
228
+ envelope.error,
229
+ this.token,
230
+ `Open Phiz request failed (${response.status})`
231
+ ),
232
+ {
233
+ code,
234
+ status: response.status,
235
+ ...requestId ? { requestId } : {},
236
+ retryable
237
+ }
238
+ );
239
+ }
240
+ if (!isRecord(envelope.data)) {
241
+ throw new PhizCliError("Open Phiz returned an invalid data object", {
242
+ code: "INVALID_RESPONSE",
243
+ status: response.status,
244
+ ...requestId ? { requestId } : {}
245
+ });
246
+ }
247
+ return {
248
+ data: envelope.data,
249
+ ...requestId ? { requestId } : {},
250
+ ...response.headers.get("idempotency-replayed") === "true" ? { idempotentReplay: true } : {}
251
+ };
252
+ } catch (error) {
253
+ if (error instanceof PhizCliError) throw error;
254
+ const aborted = error instanceof DOMException && error.name === "AbortError";
255
+ if (!aborted && attempt + 1 < maximumAttempts) {
256
+ await wait(this.retryDelayMs * 2 ** attempt);
257
+ continue;
258
+ }
259
+ throw new PhizCliError(
260
+ aborted ? "Open Phiz request timed out" : "Unable to reach Open Phiz",
261
+ {
262
+ code: aborted ? "TIMEOUT" : "NETWORK_ERROR",
263
+ retryable: options.retry
264
+ }
265
+ );
266
+ } finally {
267
+ clearTimeout(timeout);
268
+ }
269
+ }
270
+ throw new PhizCliError("Unable to reach Open Phiz", {
271
+ code: "NETWORK_ERROR",
272
+ retryable: options.retry
273
+ });
274
+ }
275
+ };
276
+
277
+ // src/cli.ts
278
+ var SECRET_ARGUMENTS = ["--token", "--pat", "--secret", "--app-secret"];
279
+ var MAX_CODE_PACKAGE_BYTES = 50 * 1024 * 1024;
280
+ var ZIP_MAGIC = Buffer.from([80, 75, 3, 4]);
281
+ var IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9._:-]{8,153}$/;
282
+ var LIFECYCLE_IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9._:-]{8,160}$/;
283
+ var BOOLEAN_OPTIONS = /* @__PURE__ */ new Set(["wait", "confirm", "auto-publish"]);
284
+ function usage() {
285
+ return [
286
+ "Open Phiz CLI",
287
+ "",
288
+ "Usage:",
289
+ " phiz mini-app list [--page <n>] [--page-size <n>] [--keyword <text>] [--status <value>]",
290
+ " phiz mini-app status --app-id <appId>",
291
+ " phiz mini-app upload --app-id <appId> --file <package.zip> --version <x.y.z> --remark <text> [--wait]",
292
+ " phiz mini-app review submit --app-id <appId> --version-id <id> --confirm [--auto-publish] [--wait]",
293
+ " phiz mini-app review withdraw --app-id <appId> --version-id <id> --confirm [--wait]",
294
+ " phiz mini-app publish --app-id <appId> --version-id <id> --confirm [--wait]",
295
+ " phiz mini-app unpublish --app-id <appId> --version-id <id> --confirm [--wait]",
296
+ " phiz mini-app rollback-list --app-id <appId> [--page <n>] [--page-size <n>]",
297
+ " phiz mini-app rollback --app-id <appId> --version-id <id> --confirm [--wait]",
298
+ "",
299
+ "Global options:",
300
+ " --json Emit stable machine-readable JSON",
301
+ " --base-url <url> Override PHIZ_BASE_URL",
302
+ " --allow-insecure-http Allow HTTP outside localhost for isolated development only",
303
+ " --help Show help",
304
+ " --version Show version",
305
+ "",
306
+ "Upload options:",
307
+ " --idempotency-key <key> Override the deterministic recovery key",
308
+ " --wait Poll until the draft is visible",
309
+ " --wait-timeout <sec> Poll timeout, default 120 seconds",
310
+ " --poll-interval <sec> Poll interval, default 2 seconds",
311
+ "",
312
+ "Lifecycle options:",
313
+ " --confirm Explicitly authorize a lifecycle write",
314
+ " --auto-publish Publish automatically after review approval",
315
+ " --idempotency-key <key> Override the deterministic recovery key",
316
+ " --wait Poll until the target state is visible",
317
+ "",
318
+ "Credentials:",
319
+ " Set PHIZ_TOKEN in the environment. Secret command-line arguments are rejected."
320
+ ].join("\n");
321
+ }
322
+ function parseArgs(argv) {
323
+ for (const value of argv) {
324
+ if (SECRET_ARGUMENTS.some((name) => value === name || value.startsWith(`${name}=`))) {
325
+ throw new PhizCliError("Pass credentials through PHIZ_TOKEN, not command-line arguments", {
326
+ code: "SECRET_ARGUMENT_FORBIDDEN"
327
+ });
328
+ }
329
+ }
330
+ const command = [];
331
+ const options = /* @__PURE__ */ new Map();
332
+ let json = false;
333
+ let baseUrl;
334
+ let allowInsecureHttp = false;
335
+ for (let index = 0; index < argv.length; index += 1) {
336
+ const value = argv[index];
337
+ if (!value.startsWith("--")) {
338
+ command.push(value);
339
+ continue;
340
+ }
341
+ if (value === "--json") {
342
+ json = true;
343
+ continue;
344
+ }
345
+ if (value === "--allow-insecure-http") {
346
+ allowInsecureHttp = true;
347
+ continue;
348
+ }
349
+ if (BOOLEAN_OPTIONS.has(value.slice(2))) {
350
+ options.set(value.slice(2), true);
351
+ continue;
352
+ }
353
+ if (value === "--help" || value === "--version" && argv.length === 1) {
354
+ options.set(value.slice(2), true);
355
+ continue;
356
+ }
357
+ const [inlineName, inlineValue] = value.split("=", 2);
358
+ const name = inlineName.slice(2);
359
+ if (inlineValue !== void 0 && BOOLEAN_OPTIONS.has(name)) {
360
+ throw new PhizCliError(`Option --${name} is a flag and does not accept a value`, {
361
+ code: "INVALID_ARGUMENT"
362
+ });
363
+ }
364
+ const next = inlineValue ?? argv[index + 1];
365
+ if (!next || !inlineValue && next.startsWith("--")) {
366
+ throw new PhizCliError(`Option --${name} requires a value`, { code: "INVALID_ARGUMENT" });
367
+ }
368
+ if (!inlineValue) index += 1;
369
+ if (name === "base-url") baseUrl = next;
370
+ else options.set(name, next);
371
+ }
372
+ return {
373
+ command,
374
+ options,
375
+ json,
376
+ ...baseUrl ? { baseUrl } : {},
377
+ allowInsecureHttp
378
+ };
379
+ }
380
+ function positiveInteger(value, fallback, maximum) {
381
+ if (value === void 0) return fallback;
382
+ const parsed = Number(value);
383
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > maximum) {
384
+ throw new PhizCliError(`Expected an integer from 1 to ${maximum}`, {
385
+ code: "INVALID_ARGUMENT"
386
+ });
387
+ }
388
+ return parsed;
389
+ }
390
+ function requiredOption(options, name) {
391
+ const value = options.get(name);
392
+ if (typeof value !== "string" || !value.trim()) {
393
+ throw new PhizCliError(`Missing required option --${name}`, { code: "INVALID_ARGUMENT" });
394
+ }
395
+ return value;
396
+ }
397
+ function assertOptions(options, allowed) {
398
+ for (const name of options.keys()) {
399
+ if (!allowed.includes(name)) {
400
+ throw new PhizCliError(`Unknown option --${name}`, { code: "INVALID_ARGUMENT" });
401
+ }
402
+ }
403
+ }
404
+ function outputJson(io, value) {
405
+ io.stdout(JSON.stringify(value));
406
+ }
407
+ function packageItemForVersion(data, version) {
408
+ const items = Array.isArray(data.items) ? data.items : [];
409
+ return items.find(
410
+ (item) => Boolean(item) && typeof item === "object" && !Array.isArray(item) && item.version === version
411
+ );
412
+ }
413
+ function packageId(item) {
414
+ const value = item.miniAppCompiledPackageId ?? item.miniAppVersionId ?? item.id;
415
+ return typeof value === "string" ? value : "";
416
+ }
417
+ function assertMatchingPackageDigest(item, version, sha256) {
418
+ if (item.packageSha256 !== sha256) {
419
+ throw new PhizCliError(
420
+ `Version ${version} already exists and cannot be verified against this package`,
421
+ { code: "VERSION_CONFLICT" }
422
+ );
423
+ }
424
+ if (item.versionEditionStatus !== 4) {
425
+ throw new PhizCliError(`Version ${version} already exists but is not a draft`, {
426
+ code: "VERSION_STATE_CONFLICT"
427
+ });
428
+ }
429
+ }
430
+ async function sha256File(path) {
431
+ const hash = createHash("sha256");
432
+ for await (const chunk of createReadStream(path)) hash.update(chunk);
433
+ return hash.digest("hex");
434
+ }
435
+ async function loadLocalPackage(path) {
436
+ const filename = basename(path);
437
+ let fileStat;
438
+ try {
439
+ fileStat = await lstat(path);
440
+ } catch {
441
+ throw new PhizCliError(`Package file is not readable: ${filename}`, {
442
+ code: "PACKAGE_NOT_FOUND"
443
+ });
444
+ }
445
+ if (fileStat.isSymbolicLink() || !fileStat.isFile()) {
446
+ throw new PhizCliError("Package path must be a regular file, not a link or directory", {
447
+ code: "INVALID_PACKAGE"
448
+ });
449
+ }
450
+ if (!filename.toLowerCase().endsWith(".zip")) {
451
+ throw new PhizCliError("Package file must use the .zip extension", {
452
+ code: "INVALID_PACKAGE"
453
+ });
454
+ }
455
+ if (fileStat.size === 0) {
456
+ throw new PhizCliError("Package file must not be empty", { code: "INVALID_PACKAGE" });
457
+ }
458
+ if (fileStat.size > MAX_CODE_PACKAGE_BYTES) {
459
+ throw new PhizCliError("Package exceeds the 50 MB limit", { code: "PACKAGE_TOO_LARGE" });
460
+ }
461
+ const handle = await open(path, "r");
462
+ try {
463
+ const magic = Buffer.alloc(ZIP_MAGIC.length);
464
+ const { bytesRead } = await handle.read(magic, 0, magic.length, 0);
465
+ if (bytesRead !== ZIP_MAGIC.length || !magic.equals(ZIP_MAGIC)) {
466
+ throw new PhizCliError("Package content is not a supported zip archive", {
467
+ code: "INVALID_PACKAGE"
468
+ });
469
+ }
470
+ } finally {
471
+ await handle.close();
472
+ }
473
+ try {
474
+ const [sha256, bytes] = await Promise.all([sha256File(path), readFile(path)]);
475
+ const uploadedSha256 = createHash("sha256").update(bytes).digest("hex");
476
+ if (bytes.byteLength !== fileStat.size || uploadedSha256 !== sha256) {
477
+ throw new PhizCliError("Package changed while it was being read; retry with a stable file", {
478
+ code: "PACKAGE_CHANGED",
479
+ retryable: true
480
+ });
481
+ }
482
+ return { bytes, filename, size: fileStat.size, sha256 };
483
+ } catch (error) {
484
+ if (error instanceof PhizCliError) throw error;
485
+ throw new PhizCliError(`Package file could not be read: ${filename}`, {
486
+ code: "PACKAGE_READ_FAILED"
487
+ });
488
+ }
489
+ }
490
+ function deriveIdempotencyKey(appId, version, packageSha256) {
491
+ const digest = createHash("sha256").update(`${appId}\0${version}\0${packageSha256}`).digest("hex");
492
+ return `phiz-cli-v1-${digest}`;
493
+ }
494
+ function resolveIdempotencyKey(value, appId, version, packageSha256) {
495
+ const key = typeof value === "string" ? value.trim() : deriveIdempotencyKey(appId, version, packageSha256);
496
+ if (!IDEMPOTENCY_KEY_PATTERN.test(key)) {
497
+ throw new PhizCliError(
498
+ "Idempotency key must contain 8-153 letters, digits, dots, underscores, colons, or hyphens",
499
+ { code: "INVALID_ARGUMENT" }
500
+ );
501
+ }
502
+ return key;
503
+ }
504
+ var LIFECYCLE_COMMANDS = {
505
+ "mini-app review submit": { action: "review-submit", targetSlot: "reviewVersion" },
506
+ "mini-app review withdraw": { action: "review-withdraw", targetSlot: "draftVersion" },
507
+ "mini-app publish": { action: "publish", targetSlot: "onlineVersion" },
508
+ "mini-app unpublish": {
509
+ action: "unpublish",
510
+ targetSlot: "onlineVersion",
511
+ targetAbsent: true
512
+ },
513
+ "mini-app rollback": { action: "rollback", targetSlot: "onlineVersion" }
514
+ };
515
+ function resolveLifecycleIdempotencyKey(value, action, appId, versionId, variant = "") {
516
+ const key = typeof value === "string" ? value.trim() : `phiz-cli-v1-${createHash("sha256").update(`${action}\0${appId}\0${versionId}\0${variant}`).digest("hex")}`;
517
+ if (!LIFECYCLE_IDEMPOTENCY_KEY_PATTERN.test(key)) {
518
+ throw new PhizCliError(
519
+ "Idempotency key must contain 8-160 letters, digits, dots, underscores, colons, or hyphens",
520
+ { code: "INVALID_ARGUMENT" }
521
+ );
522
+ }
523
+ return key;
524
+ }
525
+ function versionIdFromSlot(value) {
526
+ if (!value || typeof value !== "object" || Array.isArray(value)) return "";
527
+ const record = value;
528
+ const id = record.miniAppVersionId ?? record.miniAppCompiledPackageId ?? record.id;
529
+ return typeof id === "string" ? id : "";
530
+ }
531
+ function lifecycleStateVisible(data, command, versionId) {
532
+ const visibleVersionId = versionIdFromSlot(data[command.targetSlot]);
533
+ return command.targetAbsent ? visibleVersionId === "" : visibleVersionId === versionId;
534
+ }
535
+ async function queryLifecycleState(client, runtime, input) {
536
+ const now = runtime.now ?? Date.now;
537
+ const sleep = runtime.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
538
+ const deadline = now() + input.timeoutMs;
539
+ while (true) {
540
+ const result = await client.getMiniAppStatus(input.appId);
541
+ const verified = lifecycleStateVisible(result.data, input.command, input.versionId);
542
+ if (verified || !input.wait) {
543
+ return {
544
+ data: result.data,
545
+ ...result.requestId ? { requestId: result.requestId } : {},
546
+ verified
547
+ };
548
+ }
549
+ if (now() >= deadline) {
550
+ throw new PhizCliError("Timed out waiting for the lifecycle state to become visible", {
551
+ code: "WAIT_TIMEOUT",
552
+ retryable: true
553
+ });
554
+ }
555
+ await sleep(input.intervalMs);
556
+ }
557
+ }
558
+ async function waitForDraft(client, runtime, input) {
559
+ const now = runtime.now ?? Date.now;
560
+ const sleep = runtime.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
561
+ const deadline = now() + input.timeoutMs;
562
+ while (true) {
563
+ const result = await client.listCompiledPackages(input.appId);
564
+ const item = packageItemForVersion(result.data, input.version);
565
+ if (item) {
566
+ assertMatchingPackageDigest(item, input.version, input.packageSha256);
567
+ return { item, ...result.requestId ? { requestId: result.requestId } : {} };
568
+ }
569
+ if (now() >= deadline) {
570
+ throw new PhizCliError("Timed out waiting for the draft version to become visible", {
571
+ code: "WAIT_TIMEOUT",
572
+ retryable: true
573
+ });
574
+ }
575
+ await sleep(input.intervalMs);
576
+ }
577
+ }
578
+ function renderUploadResult(data) {
579
+ return [
580
+ `Draft: ${String(data.version ?? "-")}`,
581
+ `Version ID: ${String(data.versionId ?? "-")}`,
582
+ `SHA-256: ${String(data.packageSha256 ?? "-")}`,
583
+ `Size: ${String(data.packageSize ?? 0)} bytes`,
584
+ `Recovered: ${data.recovered === true ? "yes" : "no"}`
585
+ ].join("\n");
586
+ }
587
+ function formatVersionSlot(label, value) {
588
+ if (!value || typeof value !== "object" || Array.isArray(value)) return `${label}: -`;
589
+ const record = value;
590
+ return `${label}: ${String(record.version ?? "-")} (${String(record.status ?? "-")})`;
591
+ }
592
+ function renderMiniAppList(data) {
593
+ const items = Array.isArray(data.items) ? data.items : [];
594
+ if (!items.length) return "No mini apps found.";
595
+ const lines = items.map((item) => {
596
+ const record = item;
597
+ const id = record.miniAppId ?? record.appId ?? record.id ?? "-";
598
+ return `${String(id)} ${String(record.name ?? "-")} ${String(record.appStatus ?? record.status ?? "-")}`;
599
+ });
600
+ return ["APP ID NAME STATUS", ...lines, `Total: ${String(data.total ?? items.length)}`].join(
601
+ "\n"
602
+ );
603
+ }
604
+ function renderMiniAppStatus(appId, data) {
605
+ return [
606
+ `Mini app: ${appId}`,
607
+ formatVersionSlot("Online", data.onlineVersion),
608
+ formatVersionSlot("Review", data.reviewVersion),
609
+ formatVersionSlot("Trial", data.trailVersion),
610
+ formatVersionSlot("Draft", data.draftVersion)
611
+ ].join("\n");
612
+ }
613
+ function renderRollbackList(data) {
614
+ const items = Array.isArray(data.items) ? data.items : [];
615
+ if (!items.length) return "No rollback versions found.";
616
+ return [
617
+ "VERSION ID VERSION PUBLISHED AT",
618
+ ...items.map((item) => {
619
+ const record = item;
620
+ return `${String(record.miniAppVersionId ?? "-")} ${String(record.version ?? "-")} ${String(record.publishedAt ?? "-")}`;
621
+ }),
622
+ `Total: ${String(data.total ?? items.length)}`
623
+ ].join("\n");
624
+ }
625
+ function renderLifecycleResult(data) {
626
+ return [
627
+ `Action: ${String(data.action ?? "-")}`,
628
+ `Mini app: ${String(data.appId ?? "-")}`,
629
+ `Version ID: ${String(data.versionId ?? "-")}`,
630
+ `State: ${String(data.state ?? "-")}`,
631
+ `Verified: ${data.verified === true ? "yes" : "no"}`,
632
+ `Replayed: ${data.replayed === true ? "yes" : "no"}`
633
+ ].join("\n");
634
+ }
635
+ function errorPayload(error) {
636
+ return {
637
+ ok: false,
638
+ error: {
639
+ code: error.code,
640
+ message: error.message,
641
+ ...error.status !== void 0 ? { status: error.status } : {},
642
+ ...error.requestId ? { requestId: error.requestId } : {},
643
+ retryable: error.retryable
644
+ }
645
+ };
646
+ }
647
+ async function runCli(argv, runtime) {
648
+ let jsonRequested = argv.includes("--json");
649
+ try {
650
+ const parsed = parseArgs(argv);
651
+ jsonRequested = parsed.json;
652
+ if (parsed.options.has("version") && parsed.command.length === 0) {
653
+ runtime.io.stdout(CLI_VERSION);
654
+ return 0;
655
+ }
656
+ if (parsed.options.has("help") || parsed.command.length === 0) {
657
+ runtime.io.stdout(usage());
658
+ return 0;
659
+ }
660
+ const token = runtime.env.PHIZ_TOKEN?.trim();
661
+ const baseUrl = parsed.baseUrl ?? runtime.env.PHIZ_BASE_URL?.trim();
662
+ if (!token) {
663
+ throw new PhizCliError("PHIZ_TOKEN is required", { code: "CONFIG_MISSING" });
664
+ }
665
+ if (!baseUrl) {
666
+ throw new PhizCliError("PHIZ_BASE_URL is required", { code: "CONFIG_MISSING" });
667
+ }
668
+ const client = new PhizApiClient({
669
+ baseUrl,
670
+ token,
671
+ ...runtime.fetch ? { fetch: runtime.fetch } : {},
672
+ allowInsecureHttp: parsed.allowInsecureHttp || runtime.env.PHIZ_ALLOW_INSECURE_HTTP === "1"
673
+ });
674
+ const commandName = parsed.command.join(" ");
675
+ if (commandName === "mini-app list") {
676
+ assertOptions(parsed.options, ["page", "page-size", "keyword", "status"]);
677
+ const result = await client.listMiniApps({
678
+ pageNo: positiveInteger(parsed.options.get("page"), 1, 1e6),
679
+ pageSize: positiveInteger(parsed.options.get("page-size"), 20, 100),
680
+ ...typeof parsed.options.get("keyword") === "string" ? { keyword: parsed.options.get("keyword") } : {},
681
+ ...typeof parsed.options.get("status") === "string" ? { appStatus: parsed.options.get("status") } : {}
682
+ });
683
+ if (parsed.json) {
684
+ outputJson(runtime.io, {
685
+ ok: true,
686
+ command: commandName,
687
+ data: result.data,
688
+ ...result.requestId ? { requestId: result.requestId } : {}
689
+ });
690
+ } else runtime.io.stdout(renderMiniAppList(result.data));
691
+ return 0;
692
+ }
693
+ if (commandName === "mini-app status") {
694
+ assertOptions(parsed.options, ["app-id"]);
695
+ const appId = requiredOption(parsed.options, "app-id");
696
+ const result = await client.getMiniAppStatus(appId);
697
+ if (parsed.json) {
698
+ outputJson(runtime.io, {
699
+ ok: true,
700
+ command: commandName,
701
+ data: result.data,
702
+ ...result.requestId ? { requestId: result.requestId } : {}
703
+ });
704
+ } else runtime.io.stdout(renderMiniAppStatus(appId, result.data));
705
+ return 0;
706
+ }
707
+ if (commandName === "mini-app rollback-list") {
708
+ assertOptions(parsed.options, ["app-id", "page", "page-size"]);
709
+ const appId = requiredOption(parsed.options, "app-id").trim();
710
+ const result = await client.listRollbackVersions(
711
+ appId,
712
+ positiveInteger(parsed.options.get("page"), 1, 1e6),
713
+ positiveInteger(parsed.options.get("page-size"), 20, 100)
714
+ );
715
+ if (parsed.json) {
716
+ outputJson(runtime.io, {
717
+ ok: true,
718
+ command: commandName,
719
+ data: result.data,
720
+ ...result.requestId ? { requestId: result.requestId } : {}
721
+ });
722
+ } else runtime.io.stdout(renderRollbackList(result.data));
723
+ return 0;
724
+ }
725
+ if (commandName === "mini-app upload") {
726
+ assertOptions(parsed.options, [
727
+ "app-id",
728
+ "file",
729
+ "version",
730
+ "remark",
731
+ "idempotency-key",
732
+ "wait",
733
+ "wait-timeout",
734
+ "poll-interval"
735
+ ]);
736
+ const appId = requiredOption(parsed.options, "app-id").trim();
737
+ const filePath = requiredOption(parsed.options, "file");
738
+ const version = requiredOption(parsed.options, "version").trim();
739
+ const remark = requiredOption(parsed.options, "remark").trim();
740
+ if (!/^\d+\.\d+\.\d+$/.test(version)) {
741
+ throw new PhizCliError("Version must use x.y.z numeric format", {
742
+ code: "INVALID_ARGUMENT"
743
+ });
744
+ }
745
+ if (remark.length > 200) {
746
+ throw new PhizCliError("Remark must not exceed 200 characters", {
747
+ code: "INVALID_ARGUMENT"
748
+ });
749
+ }
750
+ const localPackage = await loadLocalPackage(filePath);
751
+ const idempotencyKey = resolveIdempotencyKey(
752
+ parsed.options.get("idempotency-key"),
753
+ appId,
754
+ version,
755
+ localPackage.sha256
756
+ );
757
+ const waitTimeoutSeconds = positiveInteger(parsed.options.get("wait-timeout"), 120, 3600);
758
+ const pollIntervalSeconds = positiveInteger(parsed.options.get("poll-interval"), 2, 60);
759
+ const existingResult = await client.listCompiledPackages(appId);
760
+ const existing = packageItemForVersion(existingResult.data, version);
761
+ let versionId = "";
762
+ let recovered = false;
763
+ let uploadReplay = false;
764
+ let buildReplay = false;
765
+ let requestId = existingResult.requestId;
766
+ if (existing) {
767
+ assertMatchingPackageDigest(existing, version, localPackage.sha256);
768
+ versionId = packageId(existing);
769
+ recovered = true;
770
+ } else {
771
+ const uploadResult = await client.uploadCompiledPackage({
772
+ bytes: localPackage.bytes,
773
+ filename: localPackage.filename,
774
+ packageSha256: localPackage.sha256,
775
+ idempotencyKey: `${idempotencyKey}:upload`
776
+ });
777
+ const netdiskId = uploadResult.data.netdiskID ?? uploadResult.data.netdiskId;
778
+ if (typeof netdiskId !== "string" || !netdiskId) {
779
+ throw new PhizCliError("Upload response did not include a storage ID", {
780
+ code: "INVALID_RESPONSE"
781
+ });
782
+ }
783
+ if (uploadResult.data.packageSha256 !== localPackage.sha256) {
784
+ throw new PhizCliError("Upload response digest does not match the local package", {
785
+ code: "PACKAGE_DIGEST_MISMATCH"
786
+ });
787
+ }
788
+ uploadReplay = uploadResult.idempotentReplay === true;
789
+ const buildResult = await client.buildDraft({
790
+ appId,
791
+ version,
792
+ remark,
793
+ netdiskId,
794
+ filename: localPackage.filename,
795
+ packageSha256: localPackage.sha256,
796
+ idempotencyKey: `${idempotencyKey}:build`
797
+ });
798
+ const rawVersionId = buildResult.data.miniAppCompiledPackageId ?? buildResult.data.miniAppBeforeCompiledId;
799
+ if (typeof rawVersionId !== "string" || !rawVersionId) {
800
+ throw new PhizCliError("Build response did not include a draft version ID", {
801
+ code: "INVALID_RESPONSE"
802
+ });
803
+ }
804
+ versionId = rawVersionId;
805
+ recovered = buildResult.data.recovered === true;
806
+ buildReplay = buildResult.idempotentReplay === true;
807
+ requestId = buildResult.requestId ?? uploadResult.requestId ?? requestId;
808
+ }
809
+ if (parsed.options.has("wait")) {
810
+ const waited = await waitForDraft(client, runtime, {
811
+ appId,
812
+ version,
813
+ packageSha256: localPackage.sha256,
814
+ timeoutMs: waitTimeoutSeconds * 1e3,
815
+ intervalMs: pollIntervalSeconds * 1e3
816
+ });
817
+ versionId = packageId(waited.item) || versionId;
818
+ requestId = waited.requestId ?? requestId;
819
+ }
820
+ const data = {
821
+ appId,
822
+ version,
823
+ versionId,
824
+ filename: localPackage.filename,
825
+ packageSize: localPackage.size,
826
+ packageSha256: localPackage.sha256,
827
+ recovered,
828
+ uploadReplay,
829
+ buildReplay,
830
+ waited: parsed.options.has("wait")
831
+ };
832
+ if (parsed.json) {
833
+ outputJson(runtime.io, {
834
+ ok: true,
835
+ command: commandName,
836
+ data,
837
+ ...requestId ? { requestId } : {}
838
+ });
839
+ } else runtime.io.stdout(renderUploadResult(data));
840
+ return 0;
841
+ }
842
+ const lifecycleCommand = LIFECYCLE_COMMANDS[commandName];
843
+ if (lifecycleCommand) {
844
+ const allowedOptions = [
845
+ "app-id",
846
+ "version-id",
847
+ "confirm",
848
+ "idempotency-key",
849
+ "wait",
850
+ "wait-timeout",
851
+ "poll-interval",
852
+ ...lifecycleCommand.action === "review-submit" ? ["auto-publish"] : []
853
+ ];
854
+ assertOptions(parsed.options, allowedOptions);
855
+ const appId = requiredOption(parsed.options, "app-id").trim();
856
+ const versionId = requiredOption(parsed.options, "version-id").trim();
857
+ if (parsed.options.get("confirm") !== true) {
858
+ throw new PhizCliError("Lifecycle writes require the explicit --confirm flag", {
859
+ code: "CONFIRMATION_REQUIRED"
860
+ });
861
+ }
862
+ if (parsed.options.has("auto-publish") && parsed.options.get("auto-publish") !== true) {
863
+ throw new PhizCliError("--auto-publish is a flag and does not accept a value", {
864
+ code: "INVALID_ARGUMENT"
865
+ });
866
+ }
867
+ const waitTimeoutSeconds = positiveInteger(parsed.options.get("wait-timeout"), 120, 3600);
868
+ const pollIntervalSeconds = positiveInteger(parsed.options.get("poll-interval"), 2, 60);
869
+ const idempotencyKey = resolveLifecycleIdempotencyKey(
870
+ parsed.options.get("idempotency-key"),
871
+ lifecycleCommand.action,
872
+ appId,
873
+ versionId,
874
+ lifecycleCommand.action === "review-submit" ? String(parsed.options.get("auto-publish") === true) : ""
875
+ );
876
+ const result = await client.executeVersionLifecycle({
877
+ action: lifecycleCommand.action,
878
+ appId,
879
+ versionId,
880
+ idempotencyKey,
881
+ ...lifecycleCommand.action === "review-submit" ? { autoPublish: parsed.options.get("auto-publish") === true } : {}
882
+ });
883
+ const state = await queryLifecycleState(client, runtime, {
884
+ appId,
885
+ versionId,
886
+ command: lifecycleCommand,
887
+ wait: parsed.options.get("wait") === true,
888
+ timeoutMs: waitTimeoutSeconds * 1e3,
889
+ intervalMs: pollIntervalSeconds * 1e3
890
+ });
891
+ const data = {
892
+ ...result.data,
893
+ action: lifecycleCommand.action,
894
+ appId,
895
+ versionId,
896
+ replayed: result.idempotentReplay === true,
897
+ verified: state.verified,
898
+ status: state.data,
899
+ ...state.requestId ? { statusRequestId: state.requestId } : {}
900
+ };
901
+ if (parsed.json) {
902
+ outputJson(runtime.io, {
903
+ ok: true,
904
+ command: commandName,
905
+ data,
906
+ ...result.requestId ? { requestId: result.requestId } : {}
907
+ });
908
+ } else runtime.io.stdout(renderLifecycleResult(data));
909
+ return 0;
910
+ }
911
+ throw new PhizCliError(`Unknown command: ${commandName}`, { code: "UNKNOWN_COMMAND" });
912
+ } catch (error) {
913
+ const normalized = error instanceof PhizCliError ? error : new PhizCliError(error instanceof Error ? error.message : "Unexpected CLI error", {
914
+ code: error instanceof TypeError ? "CONFIG_INVALID" : "CLI_ERROR"
915
+ });
916
+ if (jsonRequested) outputJson(runtime.io, errorPayload(normalized));
917
+ else runtime.io.stderr(`${normalized.code}: ${normalized.message}`);
918
+ return ["INVALID_ARGUMENT", "UNKNOWN_COMMAND", "CONFIRMATION_REQUIRED"].includes(
919
+ normalized.code
920
+ ) ? 2 : 1;
921
+ }
922
+ }
923
+
924
+ // src/index.ts
925
+ var exitCode = await runCli(process.argv.slice(2), {
926
+ env: process.env,
927
+ io: {
928
+ stdout: (value) => process.stdout.write(`${value}
929
+ `),
930
+ stderr: (value) => process.stderr.write(`${value}
931
+ `)
932
+ }
933
+ });
934
+ process.exitCode = exitCode;
935
+ //# sourceMappingURL=index.js.map
936
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts","../src/client.ts","../src/cli.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["declare const __OPEN_PHIZ_CLI_VERSION__: string | undefined;\n\nexport const CLI_VERSION =\n typeof __OPEN_PHIZ_CLI_VERSION__ === 'string' ? __OPEN_PHIZ_CLI_VERSION__ : '0.0.0';\n","import { CLI_VERSION } from './version';\n\nexport interface PhizApiClientOptions {\n baseUrl: string;\n token: string;\n fetch?: typeof globalThis.fetch;\n timeoutMs?: number;\n retryCount?: number;\n retryDelayMs?: number;\n allowInsecureHttp?: boolean;\n}\n\nexport interface MiniAppListInput {\n pageNo: number;\n pageSize: number;\n keyword?: string;\n appStatus?: string;\n}\n\nexport interface UploadCompiledPackageInput {\n bytes: Uint8Array;\n filename: string;\n packageSha256: string;\n idempotencyKey: string;\n}\n\nexport interface BuildDraftInput {\n appId: string;\n version: string;\n remark: string;\n netdiskId: string;\n filename: string;\n packageSha256: string;\n idempotencyKey: string;\n}\n\nexport type VersionLifecycleAction =\n | 'review-submit'\n | 'review-withdraw'\n | 'publish'\n | 'unpublish'\n | 'rollback';\n\nexport interface VersionLifecycleInput {\n action: VersionLifecycleAction;\n appId: string;\n versionId: string;\n idempotencyKey: string;\n autoPublish?: boolean;\n}\n\nexport interface ApiResult<T> {\n data: T;\n requestId?: string;\n idempotentReplay?: boolean;\n}\n\ninterface ApiEnvelope {\n errcode?: unknown;\n error?: unknown;\n data?: unknown;\n}\n\ninterface RequestBody {\n body: BodyInit;\n headers?: HeadersInit;\n}\n\nconst DEFAULT_TIMEOUT_MS = 15_000;\nconst DEFAULT_RETRY_COUNT = 2;\nconst DEFAULT_RETRY_DELAY_MS = 250;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction normalizeBaseUrl(value: string, allowInsecureHttp: boolean): URL {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new TypeError('PHIZ_BASE_URL must be a valid HTTP(S) URL');\n }\n if (!['http:', 'https:'].includes(url.protocol)) {\n throw new TypeError('PHIZ_BASE_URL must use HTTP or HTTPS');\n }\n if (url.username || url.password || url.search || url.hash) {\n throw new TypeError(\n 'PHIZ_BASE_URL must not contain credentials, query parameters, or a fragment'\n );\n }\n const localHostnames = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);\n if (url.protocol === 'http:' && !allowInsecureHttp && !localHostnames.has(url.hostname)) {\n throw new TypeError('PHIZ_BASE_URL must use HTTPS outside localhost');\n }\n url.pathname = `${url.pathname.replace(/\\/+$/, '')}/`;\n return url;\n}\n\nfunction safeMessage(value: unknown, token: string, fallback: string): string {\n const message =\n typeof value === 'string'\n ? value\n : isRecord(value) && typeof value.message === 'string'\n ? value.message\n : '';\n if (!message.trim()) return fallback;\n return message.replaceAll(token, '[REDACTED]');\n}\n\nfunction envelopeErrorCode(envelope: ApiEnvelope, status: number): string {\n if (typeof envelope.errcode === 'string' && envelope.errcode) return envelope.errcode;\n if (isRecord(envelope.error) && typeof envelope.error.code === 'string' && envelope.error.code) {\n return envelope.error.code;\n }\n return `HTTP_${status}`;\n}\n\nfunction requestIdFrom(response: Response): string | undefined {\n return response.headers.get('x-request-id') ?? undefined;\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport class PhizCliError extends Error {\n readonly code: string;\n readonly status: number | undefined;\n readonly requestId: string | undefined;\n readonly retryable: boolean;\n\n constructor(\n message: string,\n options: { code: string; status?: number; requestId?: string; retryable?: boolean }\n ) {\n super(message);\n this.name = 'PhizCliError';\n this.code = options.code;\n this.status = options.status;\n this.requestId = options.requestId;\n this.retryable = options.retryable ?? false;\n }\n}\n\nexport class PhizApiClient {\n private readonly baseUrl: URL;\n private readonly token: string;\n private readonly fetchImpl: typeof globalThis.fetch;\n private readonly timeoutMs: number;\n private readonly retryCount: number;\n private readonly retryDelayMs: number;\n\n constructor(options: PhizApiClientOptions) {\n if (!options.token.startsWith('phiz_')) {\n throw new TypeError('PHIZ_TOKEN must be a Personal Access Token beginning with phiz_');\n }\n this.baseUrl = normalizeBaseUrl(options.baseUrl, options.allowInsecureHttp ?? false);\n this.token = options.token;\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.retryCount = options.retryCount ?? DEFAULT_RETRY_COUNT;\n this.retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;\n }\n\n async listMiniApps(input: MiniAppListInput): Promise<ApiResult<Record<string, unknown>>> {\n const params = new URLSearchParams({\n pageNo: String(input.pageNo),\n pageSize: String(input.pageSize),\n });\n if (input.keyword) params.set('keyword', input.keyword);\n if (input.appStatus) params.set('appStatus', input.appStatus);\n return this.request('GET', 'dev/mini-apps/list', { params, retry: true });\n }\n\n async getMiniAppStatus(appId: string): Promise<ApiResult<Record<string, unknown>>> {\n return this.request('GET', 'dev/mini-apps/versions/latest', {\n params: new URLSearchParams({ miniAppId: appId }),\n retry: true,\n });\n }\n\n async listCompiledPackages(\n appId: string,\n pageSize = 100\n ): Promise<ApiResult<Record<string, unknown>>> {\n return this.request('GET', 'dev/mini-apps/compiled-package/list', {\n params: new URLSearchParams({ miniAppId: appId, pageNo: '1', pageSize: String(pageSize) }),\n retry: true,\n });\n }\n\n async uploadCompiledPackage(\n input: UploadCompiledPackageInput\n ): Promise<ApiResult<Record<string, unknown>>> {\n return this.request('POST', 'dev/mini-apps/compiled-package/upload', {\n retry: true,\n timeoutMs: 120_000,\n headers: {\n 'Idempotency-Key': input.idempotencyKey,\n 'X-Content-SHA256': input.packageSha256,\n },\n body: () => {\n const formData = new FormData();\n const bytes = Uint8Array.from(input.bytes);\n formData.append(\n 'file',\n new File([bytes.buffer], input.filename, { type: 'application/zip' })\n );\n return { body: formData };\n },\n });\n }\n\n async buildDraft(input: BuildDraftInput): Promise<ApiResult<Record<string, unknown>>> {\n return this.request('POST', 'dev/mini-apps/compiled-package/build', {\n retry: true,\n timeoutMs: 60_000,\n headers: {\n 'Content-Type': 'application/json',\n 'Idempotency-Key': input.idempotencyKey,\n },\n body: () => ({\n body: JSON.stringify({\n version: input.version,\n versionRemark: input.remark,\n miniAppId: input.appId,\n filesFromNetdisk: [{ netdiskID: input.netdiskId, name: input.filename }],\n packages: [],\n packageConfig: {},\n packageSha256: input.packageSha256,\n }),\n }),\n });\n }\n\n async listRollbackVersions(\n appId: string,\n pageNo: number,\n pageSize: number\n ): Promise<ApiResult<Record<string, unknown>>> {\n return this.request('GET', 'dev/mini-apps/versions/rollback/list', {\n params: new URLSearchParams({\n miniAppId: appId,\n pageNo: String(pageNo),\n pageSize: String(pageSize),\n }),\n retry: true,\n });\n }\n\n async executeVersionLifecycle(\n input: VersionLifecycleInput\n ): Promise<ApiResult<Record<string, unknown>>> {\n const pathByAction: Record<VersionLifecycleAction, string> = {\n 'review-submit': 'dev/mini-apps/versions/review/submit',\n 'review-withdraw': 'dev/mini-apps/versions/review/withdraw',\n publish: 'dev/mini-apps/versions/publish',\n unpublish: 'dev/mini-apps/versions/unpublish',\n rollback: 'dev/mini-apps/versions/rollback',\n };\n const versionField =\n input.action === 'review-submit' ? 'miniAppCompiledPackageId' : 'miniAppVersionId';\n return this.request('POST', pathByAction[input.action], {\n retry: true,\n headers: {\n 'Content-Type': 'application/json',\n 'Idempotency-Key': input.idempotencyKey,\n },\n body: () => ({\n body: JSON.stringify({\n miniAppId: input.appId,\n [versionField]: input.versionId,\n ...(input.action === 'review-submit' ? { autoPub: input.autoPublish === true } : {}),\n }),\n }),\n });\n }\n\n private async request(\n method: 'GET' | 'POST',\n path: string,\n options: {\n params?: URLSearchParams;\n headers?: HeadersInit;\n body?: () => RequestBody;\n retry: boolean;\n timeoutMs?: number;\n }\n ): Promise<ApiResult<Record<string, unknown>>> {\n const url = new URL(`api/v1/open/${path}`, this.baseUrl);\n if (options.params) url.search = options.params.toString();\n const maximumAttempts = options.retry ? this.retryCount + 1 : 1;\n\n for (let attempt = 0; attempt < maximumAttempts; attempt += 1) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? this.timeoutMs);\n try {\n const requestBody = options.body?.();\n const headers = new Headers({\n Accept: 'application/json',\n Authorization: `Bearer ${this.token}`,\n 'User-Agent': `open-phiz-cli/${CLI_VERSION}`,\n });\n new Headers(options.headers).forEach((value, name) => headers.set(name, value));\n new Headers(requestBody?.headers).forEach((value, name) => headers.set(name, value));\n const response = await this.fetchImpl(url, {\n method,\n redirect: 'error',\n headers,\n ...(requestBody ? { body: requestBody.body } : {}),\n signal: controller.signal,\n });\n const requestId = requestIdFrom(response);\n\n let envelope: ApiEnvelope;\n try {\n envelope = (await response.json()) as ApiEnvelope;\n } catch {\n throw new PhizCliError('Open Phiz returned an invalid JSON response', {\n code: 'INVALID_RESPONSE',\n status: response.status,\n ...(requestId ? { requestId } : {}),\n retryable: response.status === 429 || response.status >= 500,\n });\n }\n\n const retryable =\n response.status === 429 ||\n response.status >= 500 ||\n (response.status === 409 &&\n envelopeErrorCode(envelope, response.status) === 'IDEMPOTENCY_IN_PROGRESS');\n if (retryable && attempt + 1 < maximumAttempts) {\n await wait(this.retryDelayMs * 2 ** attempt);\n continue;\n }\n if (!response.ok || (envelope.errcode !== undefined && envelope.errcode !== 'OK')) {\n const code = envelopeErrorCode(envelope, response.status);\n throw new PhizCliError(\n safeMessage(\n envelope.error,\n this.token,\n `Open Phiz request failed (${response.status})`\n ),\n {\n code,\n status: response.status,\n ...(requestId ? { requestId } : {}),\n retryable,\n }\n );\n }\n if (!isRecord(envelope.data)) {\n throw new PhizCliError('Open Phiz returned an invalid data object', {\n code: 'INVALID_RESPONSE',\n status: response.status,\n ...(requestId ? { requestId } : {}),\n });\n }\n return {\n data: envelope.data,\n ...(requestId ? { requestId } : {}),\n ...(response.headers.get('idempotency-replayed') === 'true'\n ? { idempotentReplay: true }\n : {}),\n };\n } catch (error) {\n if (error instanceof PhizCliError) throw error;\n const aborted = error instanceof DOMException && error.name === 'AbortError';\n if (!aborted && attempt + 1 < maximumAttempts) {\n await wait(this.retryDelayMs * 2 ** attempt);\n continue;\n }\n throw new PhizCliError(\n aborted ? 'Open Phiz request timed out' : 'Unable to reach Open Phiz',\n {\n code: aborted ? 'TIMEOUT' : 'NETWORK_ERROR',\n retryable: options.retry,\n }\n );\n } finally {\n clearTimeout(timeout);\n }\n }\n throw new PhizCliError('Unable to reach Open Phiz', {\n code: 'NETWORK_ERROR',\n retryable: options.retry,\n });\n }\n}\n","import { createHash } from 'node:crypto';\nimport { createReadStream } from 'node:fs';\nimport { lstat, open, readFile } from 'node:fs/promises';\nimport { basename } from 'node:path';\n\nimport { PhizApiClient, PhizCliError, type VersionLifecycleAction } from './client';\nimport { CLI_VERSION } from './version';\n\nexport interface CliIo {\n stdout: (value: string) => void;\n stderr: (value: string) => void;\n}\n\nexport interface CliRuntime {\n env: Record<string, string | undefined>;\n fetch?: typeof globalThis.fetch;\n sleep?: (milliseconds: number) => Promise<void>;\n now?: () => number;\n io: CliIo;\n}\n\ninterface ParsedArgs {\n command: string[];\n options: Map<string, string | true>;\n json: boolean;\n baseUrl?: string;\n allowInsecureHttp: boolean;\n}\n\nconst SECRET_ARGUMENTS = ['--token', '--pat', '--secret', '--app-secret'];\nconst MAX_CODE_PACKAGE_BYTES = 50 * 1024 * 1024;\nconst ZIP_MAGIC = Buffer.from([0x50, 0x4b, 0x03, 0x04]);\nconst IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9._:-]{8,153}$/;\nconst LIFECYCLE_IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9._:-]{8,160}$/;\nconst BOOLEAN_OPTIONS = new Set(['wait', 'confirm', 'auto-publish']);\n\nfunction usage(): string {\n return [\n 'Open Phiz CLI',\n '',\n 'Usage:',\n ' phiz mini-app list [--page <n>] [--page-size <n>] [--keyword <text>] [--status <value>]',\n ' phiz mini-app status --app-id <appId>',\n ' phiz mini-app upload --app-id <appId> --file <package.zip> --version <x.y.z> --remark <text> [--wait]',\n ' phiz mini-app review submit --app-id <appId> --version-id <id> --confirm [--auto-publish] [--wait]',\n ' phiz mini-app review withdraw --app-id <appId> --version-id <id> --confirm [--wait]',\n ' phiz mini-app publish --app-id <appId> --version-id <id> --confirm [--wait]',\n ' phiz mini-app unpublish --app-id <appId> --version-id <id> --confirm [--wait]',\n ' phiz mini-app rollback-list --app-id <appId> [--page <n>] [--page-size <n>]',\n ' phiz mini-app rollback --app-id <appId> --version-id <id> --confirm [--wait]',\n '',\n 'Global options:',\n ' --json Emit stable machine-readable JSON',\n ' --base-url <url> Override PHIZ_BASE_URL',\n ' --allow-insecure-http Allow HTTP outside localhost for isolated development only',\n ' --help Show help',\n ' --version Show version',\n '',\n 'Upload options:',\n ' --idempotency-key <key> Override the deterministic recovery key',\n ' --wait Poll until the draft is visible',\n ' --wait-timeout <sec> Poll timeout, default 120 seconds',\n ' --poll-interval <sec> Poll interval, default 2 seconds',\n '',\n 'Lifecycle options:',\n ' --confirm Explicitly authorize a lifecycle write',\n ' --auto-publish Publish automatically after review approval',\n ' --idempotency-key <key> Override the deterministic recovery key',\n ' --wait Poll until the target state is visible',\n '',\n 'Credentials:',\n ' Set PHIZ_TOKEN in the environment. Secret command-line arguments are rejected.',\n ].join('\\n');\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n for (const value of argv) {\n if (SECRET_ARGUMENTS.some((name) => value === name || value.startsWith(`${name}=`))) {\n throw new PhizCliError('Pass credentials through PHIZ_TOKEN, not command-line arguments', {\n code: 'SECRET_ARGUMENT_FORBIDDEN',\n });\n }\n }\n\n const command: string[] = [];\n const options = new Map<string, string | true>();\n let json = false;\n let baseUrl: string | undefined;\n let allowInsecureHttp = false;\n\n for (let index = 0; index < argv.length; index += 1) {\n const value = argv[index]!;\n if (!value.startsWith('--')) {\n command.push(value);\n continue;\n }\n if (value === '--json') {\n json = true;\n continue;\n }\n if (value === '--allow-insecure-http') {\n allowInsecureHttp = true;\n continue;\n }\n if (BOOLEAN_OPTIONS.has(value.slice(2))) {\n options.set(value.slice(2), true);\n continue;\n }\n if (value === '--help' || (value === '--version' && argv.length === 1)) {\n options.set(value.slice(2), true);\n continue;\n }\n const [inlineName, inlineValue] = value.split('=', 2);\n const name = inlineName!.slice(2);\n if (inlineValue !== undefined && BOOLEAN_OPTIONS.has(name)) {\n throw new PhizCliError(`Option --${name} is a flag and does not accept a value`, {\n code: 'INVALID_ARGUMENT',\n });\n }\n const next = inlineValue ?? argv[index + 1];\n if (!next || (!inlineValue && next.startsWith('--'))) {\n throw new PhizCliError(`Option --${name} requires a value`, { code: 'INVALID_ARGUMENT' });\n }\n if (!inlineValue) index += 1;\n if (name === 'base-url') baseUrl = next;\n else options.set(name, next);\n }\n return {\n command,\n options,\n json,\n ...(baseUrl ? { baseUrl } : {}),\n allowInsecureHttp,\n };\n}\n\nfunction positiveInteger(\n value: string | true | undefined,\n fallback: number,\n maximum: number\n): number {\n if (value === undefined) return fallback;\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed < 1 || parsed > maximum) {\n throw new PhizCliError(`Expected an integer from 1 to ${maximum}`, {\n code: 'INVALID_ARGUMENT',\n });\n }\n return parsed;\n}\n\nfunction requiredOption(options: Map<string, string | true>, name: string): string {\n const value = options.get(name);\n if (typeof value !== 'string' || !value.trim()) {\n throw new PhizCliError(`Missing required option --${name}`, { code: 'INVALID_ARGUMENT' });\n }\n return value;\n}\n\nfunction assertOptions(options: Map<string, string | true>, allowed: string[]): void {\n for (const name of options.keys()) {\n if (!allowed.includes(name)) {\n throw new PhizCliError(`Unknown option --${name}`, { code: 'INVALID_ARGUMENT' });\n }\n }\n}\n\nfunction outputJson(io: CliIo, value: unknown): void {\n io.stdout(JSON.stringify(value));\n}\n\ninterface LocalPackage {\n bytes: Uint8Array;\n filename: string;\n size: number;\n sha256: string;\n}\n\nfunction packageItemForVersion(\n data: Record<string, unknown>,\n version: string\n): Record<string, unknown> | undefined {\n const items = Array.isArray(data.items) ? data.items : [];\n return items.find(\n (item): item is Record<string, unknown> =>\n Boolean(item) &&\n typeof item === 'object' &&\n !Array.isArray(item) &&\n (item as Record<string, unknown>).version === version\n );\n}\n\nfunction packageId(item: Record<string, unknown>): string {\n const value = item.miniAppCompiledPackageId ?? item.miniAppVersionId ?? item.id;\n return typeof value === 'string' ? value : '';\n}\n\nfunction assertMatchingPackageDigest(\n item: Record<string, unknown>,\n version: string,\n sha256: string\n): void {\n if (item.packageSha256 !== sha256) {\n throw new PhizCliError(\n `Version ${version} already exists and cannot be verified against this package`,\n { code: 'VERSION_CONFLICT' }\n );\n }\n if (item.versionEditionStatus !== 4) {\n throw new PhizCliError(`Version ${version} already exists but is not a draft`, {\n code: 'VERSION_STATE_CONFLICT',\n });\n }\n}\n\nasync function sha256File(path: string): Promise<string> {\n const hash = createHash('sha256');\n for await (const chunk of createReadStream(path)) hash.update(chunk as Buffer);\n return hash.digest('hex');\n}\n\nasync function loadLocalPackage(path: string): Promise<LocalPackage> {\n const filename = basename(path);\n let fileStat;\n try {\n fileStat = await lstat(path);\n } catch {\n throw new PhizCliError(`Package file is not readable: ${filename}`, {\n code: 'PACKAGE_NOT_FOUND',\n });\n }\n if (fileStat.isSymbolicLink() || !fileStat.isFile()) {\n throw new PhizCliError('Package path must be a regular file, not a link or directory', {\n code: 'INVALID_PACKAGE',\n });\n }\n if (!filename.toLowerCase().endsWith('.zip')) {\n throw new PhizCliError('Package file must use the .zip extension', {\n code: 'INVALID_PACKAGE',\n });\n }\n if (fileStat.size === 0) {\n throw new PhizCliError('Package file must not be empty', { code: 'INVALID_PACKAGE' });\n }\n if (fileStat.size > MAX_CODE_PACKAGE_BYTES) {\n throw new PhizCliError('Package exceeds the 50 MB limit', { code: 'PACKAGE_TOO_LARGE' });\n }\n\n const handle = await open(path, 'r');\n try {\n const magic = Buffer.alloc(ZIP_MAGIC.length);\n const { bytesRead } = await handle.read(magic, 0, magic.length, 0);\n if (bytesRead !== ZIP_MAGIC.length || !magic.equals(ZIP_MAGIC)) {\n throw new PhizCliError('Package content is not a supported zip archive', {\n code: 'INVALID_PACKAGE',\n });\n }\n } finally {\n await handle.close();\n }\n\n try {\n const [sha256, bytes] = await Promise.all([sha256File(path), readFile(path)]);\n const uploadedSha256 = createHash('sha256').update(bytes).digest('hex');\n if (bytes.byteLength !== fileStat.size || uploadedSha256 !== sha256) {\n throw new PhizCliError('Package changed while it was being read; retry with a stable file', {\n code: 'PACKAGE_CHANGED',\n retryable: true,\n });\n }\n return { bytes, filename, size: fileStat.size, sha256 };\n } catch (error) {\n if (error instanceof PhizCliError) throw error;\n throw new PhizCliError(`Package file could not be read: ${filename}`, {\n code: 'PACKAGE_READ_FAILED',\n });\n }\n}\n\nfunction deriveIdempotencyKey(appId: string, version: string, packageSha256: string): string {\n const digest = createHash('sha256')\n .update(`${appId}\\0${version}\\0${packageSha256}`)\n .digest('hex');\n return `phiz-cli-v1-${digest}`;\n}\n\nfunction resolveIdempotencyKey(\n value: string | true | undefined,\n appId: string,\n version: string,\n packageSha256: string\n): string {\n const key =\n typeof value === 'string' ? value.trim() : deriveIdempotencyKey(appId, version, packageSha256);\n if (!IDEMPOTENCY_KEY_PATTERN.test(key)) {\n throw new PhizCliError(\n 'Idempotency key must contain 8-153 letters, digits, dots, underscores, colons, or hyphens',\n { code: 'INVALID_ARGUMENT' }\n );\n }\n return key;\n}\n\ninterface LifecycleCommand {\n action: VersionLifecycleAction;\n targetSlot: 'reviewVersion' | 'draftVersion' | 'onlineVersion';\n targetAbsent?: boolean;\n}\n\nconst LIFECYCLE_COMMANDS: Record<string, LifecycleCommand> = {\n 'mini-app review submit': { action: 'review-submit', targetSlot: 'reviewVersion' },\n 'mini-app review withdraw': { action: 'review-withdraw', targetSlot: 'draftVersion' },\n 'mini-app publish': { action: 'publish', targetSlot: 'onlineVersion' },\n 'mini-app unpublish': {\n action: 'unpublish',\n targetSlot: 'onlineVersion',\n targetAbsent: true,\n },\n 'mini-app rollback': { action: 'rollback', targetSlot: 'onlineVersion' },\n};\n\nfunction resolveLifecycleIdempotencyKey(\n value: string | true | undefined,\n action: VersionLifecycleAction,\n appId: string,\n versionId: string,\n variant = ''\n): string {\n const key =\n typeof value === 'string'\n ? value.trim()\n : `phiz-cli-v1-${createHash('sha256')\n .update(`${action}\\0${appId}\\0${versionId}\\0${variant}`)\n .digest('hex')}`;\n if (!LIFECYCLE_IDEMPOTENCY_KEY_PATTERN.test(key)) {\n throw new PhizCliError(\n 'Idempotency key must contain 8-160 letters, digits, dots, underscores, colons, or hyphens',\n { code: 'INVALID_ARGUMENT' }\n );\n }\n return key;\n}\n\nfunction versionIdFromSlot(value: unknown): string {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return '';\n const record = value as Record<string, unknown>;\n const id = record.miniAppVersionId ?? record.miniAppCompiledPackageId ?? record.id;\n return typeof id === 'string' ? id : '';\n}\n\nfunction lifecycleStateVisible(\n data: Record<string, unknown>,\n command: LifecycleCommand,\n versionId: string\n): boolean {\n const visibleVersionId = versionIdFromSlot(data[command.targetSlot]);\n return command.targetAbsent ? visibleVersionId === '' : visibleVersionId === versionId;\n}\n\nasync function queryLifecycleState(\n client: PhizApiClient,\n runtime: CliRuntime,\n input: {\n appId: string;\n versionId: string;\n command: LifecycleCommand;\n wait: boolean;\n timeoutMs: number;\n intervalMs: number;\n }\n): Promise<{ data: Record<string, unknown>; requestId?: string; verified: boolean }> {\n const now = runtime.now ?? Date.now;\n const sleep =\n runtime.sleep ??\n ((milliseconds: number) => new Promise((resolve) => setTimeout(resolve, milliseconds)));\n const deadline = now() + input.timeoutMs;\n while (true) {\n const result = await client.getMiniAppStatus(input.appId);\n const verified = lifecycleStateVisible(result.data, input.command, input.versionId);\n if (verified || !input.wait) {\n return {\n data: result.data,\n ...(result.requestId ? { requestId: result.requestId } : {}),\n verified,\n };\n }\n if (now() >= deadline) {\n throw new PhizCliError('Timed out waiting for the lifecycle state to become visible', {\n code: 'WAIT_TIMEOUT',\n retryable: true,\n });\n }\n await sleep(input.intervalMs);\n }\n}\n\nasync function waitForDraft(\n client: PhizApiClient,\n runtime: CliRuntime,\n input: {\n appId: string;\n version: string;\n packageSha256: string;\n timeoutMs: number;\n intervalMs: number;\n }\n): Promise<{ item: Record<string, unknown>; requestId?: string }> {\n const now = runtime.now ?? Date.now;\n const sleep =\n runtime.sleep ??\n ((milliseconds: number) => new Promise((resolve) => setTimeout(resolve, milliseconds)));\n const deadline = now() + input.timeoutMs;\n while (true) {\n const result = await client.listCompiledPackages(input.appId);\n const item = packageItemForVersion(result.data, input.version);\n if (item) {\n assertMatchingPackageDigest(item, input.version, input.packageSha256);\n return { item, ...(result.requestId ? { requestId: result.requestId } : {}) };\n }\n if (now() >= deadline) {\n throw new PhizCliError('Timed out waiting for the draft version to become visible', {\n code: 'WAIT_TIMEOUT',\n retryable: true,\n });\n }\n await sleep(input.intervalMs);\n }\n}\n\nfunction renderUploadResult(data: Record<string, unknown>): string {\n return [\n `Draft: ${String(data.version ?? '-')}`,\n `Version ID: ${String(data.versionId ?? '-')}`,\n `SHA-256: ${String(data.packageSha256 ?? '-')}`,\n `Size: ${String(data.packageSize ?? 0)} bytes`,\n `Recovered: ${data.recovered === true ? 'yes' : 'no'}`,\n ].join('\\n');\n}\n\nfunction formatVersionSlot(label: string, value: unknown): string {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return `${label}: -`;\n const record = value as Record<string, unknown>;\n return `${label}: ${String(record.version ?? '-')} (${String(record.status ?? '-')})`;\n}\n\nfunction renderMiniAppList(data: Record<string, unknown>): string {\n const items = Array.isArray(data.items) ? data.items : [];\n if (!items.length) return 'No mini apps found.';\n const lines = items.map((item) => {\n const record = item as Record<string, unknown>;\n const id = record.miniAppId ?? record.appId ?? record.id ?? '-';\n return `${String(id)}\\t${String(record.name ?? '-')}\\t${String(record.appStatus ?? record.status ?? '-')}`;\n });\n return ['APP ID\\tNAME\\tSTATUS', ...lines, `Total: ${String(data.total ?? items.length)}`].join(\n '\\n'\n );\n}\n\nfunction renderMiniAppStatus(appId: string, data: Record<string, unknown>): string {\n return [\n `Mini app: ${appId}`,\n formatVersionSlot('Online', data.onlineVersion),\n formatVersionSlot('Review', data.reviewVersion),\n formatVersionSlot('Trial', data.trailVersion),\n formatVersionSlot('Draft', data.draftVersion),\n ].join('\\n');\n}\n\nfunction renderRollbackList(data: Record<string, unknown>): string {\n const items = Array.isArray(data.items) ? data.items : [];\n if (!items.length) return 'No rollback versions found.';\n return [\n 'VERSION ID\\tVERSION\\tPUBLISHED AT',\n ...items.map((item) => {\n const record = item as Record<string, unknown>;\n return `${String(record.miniAppVersionId ?? '-')}\\t${String(record.version ?? '-')}\\t${String(record.publishedAt ?? '-')}`;\n }),\n `Total: ${String(data.total ?? items.length)}`,\n ].join('\\n');\n}\n\nfunction renderLifecycleResult(data: Record<string, unknown>): string {\n return [\n `Action: ${String(data.action ?? '-')}`,\n `Mini app: ${String(data.appId ?? '-')}`,\n `Version ID: ${String(data.versionId ?? '-')}`,\n `State: ${String(data.state ?? '-')}`,\n `Verified: ${data.verified === true ? 'yes' : 'no'}`,\n `Replayed: ${data.replayed === true ? 'yes' : 'no'}`,\n ].join('\\n');\n}\n\nfunction errorPayload(error: PhizCliError) {\n return {\n ok: false,\n error: {\n code: error.code,\n message: error.message,\n ...(error.status !== undefined ? { status: error.status } : {}),\n ...(error.requestId ? { requestId: error.requestId } : {}),\n retryable: error.retryable,\n },\n };\n}\n\nexport async function runCli(argv: string[], runtime: CliRuntime): Promise<number> {\n let jsonRequested = argv.includes('--json');\n try {\n const parsed = parseArgs(argv);\n jsonRequested = parsed.json;\n if (parsed.options.has('version') && parsed.command.length === 0) {\n runtime.io.stdout(CLI_VERSION);\n return 0;\n }\n if (parsed.options.has('help') || parsed.command.length === 0) {\n runtime.io.stdout(usage());\n return 0;\n }\n\n const token = runtime.env.PHIZ_TOKEN?.trim();\n const baseUrl = parsed.baseUrl ?? runtime.env.PHIZ_BASE_URL?.trim();\n if (!token) {\n throw new PhizCliError('PHIZ_TOKEN is required', { code: 'CONFIG_MISSING' });\n }\n if (!baseUrl) {\n throw new PhizCliError('PHIZ_BASE_URL is required', { code: 'CONFIG_MISSING' });\n }\n const client = new PhizApiClient({\n baseUrl,\n token,\n ...(runtime.fetch ? { fetch: runtime.fetch } : {}),\n allowInsecureHttp: parsed.allowInsecureHttp || runtime.env.PHIZ_ALLOW_INSECURE_HTTP === '1',\n });\n\n const commandName = parsed.command.join(' ');\n if (commandName === 'mini-app list') {\n assertOptions(parsed.options, ['page', 'page-size', 'keyword', 'status']);\n const result = await client.listMiniApps({\n pageNo: positiveInteger(parsed.options.get('page'), 1, 1_000_000),\n pageSize: positiveInteger(parsed.options.get('page-size'), 20, 100),\n ...(typeof parsed.options.get('keyword') === 'string'\n ? { keyword: parsed.options.get('keyword') as string }\n : {}),\n ...(typeof parsed.options.get('status') === 'string'\n ? { appStatus: parsed.options.get('status') as string }\n : {}),\n });\n if (parsed.json) {\n outputJson(runtime.io, {\n ok: true,\n command: commandName,\n data: result.data,\n ...(result.requestId ? { requestId: result.requestId } : {}),\n });\n } else runtime.io.stdout(renderMiniAppList(result.data));\n return 0;\n }\n\n if (commandName === 'mini-app status') {\n assertOptions(parsed.options, ['app-id']);\n const appId = requiredOption(parsed.options, 'app-id');\n const result = await client.getMiniAppStatus(appId);\n if (parsed.json) {\n outputJson(runtime.io, {\n ok: true,\n command: commandName,\n data: result.data,\n ...(result.requestId ? { requestId: result.requestId } : {}),\n });\n } else runtime.io.stdout(renderMiniAppStatus(appId, result.data));\n return 0;\n }\n\n if (commandName === 'mini-app rollback-list') {\n assertOptions(parsed.options, ['app-id', 'page', 'page-size']);\n const appId = requiredOption(parsed.options, 'app-id').trim();\n const result = await client.listRollbackVersions(\n appId,\n positiveInteger(parsed.options.get('page'), 1, 1_000_000),\n positiveInteger(parsed.options.get('page-size'), 20, 100)\n );\n if (parsed.json) {\n outputJson(runtime.io, {\n ok: true,\n command: commandName,\n data: result.data,\n ...(result.requestId ? { requestId: result.requestId } : {}),\n });\n } else runtime.io.stdout(renderRollbackList(result.data));\n return 0;\n }\n\n if (commandName === 'mini-app upload') {\n assertOptions(parsed.options, [\n 'app-id',\n 'file',\n 'version',\n 'remark',\n 'idempotency-key',\n 'wait',\n 'wait-timeout',\n 'poll-interval',\n ]);\n const appId = requiredOption(parsed.options, 'app-id').trim();\n const filePath = requiredOption(parsed.options, 'file');\n const version = requiredOption(parsed.options, 'version').trim();\n const remark = requiredOption(parsed.options, 'remark').trim();\n if (!/^\\d+\\.\\d+\\.\\d+$/.test(version)) {\n throw new PhizCliError('Version must use x.y.z numeric format', {\n code: 'INVALID_ARGUMENT',\n });\n }\n if (remark.length > 200) {\n throw new PhizCliError('Remark must not exceed 200 characters', {\n code: 'INVALID_ARGUMENT',\n });\n }\n const localPackage = await loadLocalPackage(filePath);\n const idempotencyKey = resolveIdempotencyKey(\n parsed.options.get('idempotency-key'),\n appId,\n version,\n localPackage.sha256\n );\n const waitTimeoutSeconds = positiveInteger(parsed.options.get('wait-timeout'), 120, 3600);\n const pollIntervalSeconds = positiveInteger(parsed.options.get('poll-interval'), 2, 60);\n\n const existingResult = await client.listCompiledPackages(appId);\n const existing = packageItemForVersion(existingResult.data, version);\n let versionId = '';\n let recovered = false;\n let uploadReplay = false;\n let buildReplay = false;\n let requestId = existingResult.requestId;\n\n if (existing) {\n assertMatchingPackageDigest(existing, version, localPackage.sha256);\n versionId = packageId(existing);\n recovered = true;\n } else {\n const uploadResult = await client.uploadCompiledPackage({\n bytes: localPackage.bytes,\n filename: localPackage.filename,\n packageSha256: localPackage.sha256,\n idempotencyKey: `${idempotencyKey}:upload`,\n });\n const netdiskId = uploadResult.data.netdiskID ?? uploadResult.data.netdiskId;\n if (typeof netdiskId !== 'string' || !netdiskId) {\n throw new PhizCliError('Upload response did not include a storage ID', {\n code: 'INVALID_RESPONSE',\n });\n }\n if (uploadResult.data.packageSha256 !== localPackage.sha256) {\n throw new PhizCliError('Upload response digest does not match the local package', {\n code: 'PACKAGE_DIGEST_MISMATCH',\n });\n }\n uploadReplay = uploadResult.idempotentReplay === true;\n\n const buildResult = await client.buildDraft({\n appId,\n version,\n remark,\n netdiskId,\n filename: localPackage.filename,\n packageSha256: localPackage.sha256,\n idempotencyKey: `${idempotencyKey}:build`,\n });\n const rawVersionId =\n buildResult.data.miniAppCompiledPackageId ?? buildResult.data.miniAppBeforeCompiledId;\n if (typeof rawVersionId !== 'string' || !rawVersionId) {\n throw new PhizCliError('Build response did not include a draft version ID', {\n code: 'INVALID_RESPONSE',\n });\n }\n versionId = rawVersionId;\n recovered = buildResult.data.recovered === true;\n buildReplay = buildResult.idempotentReplay === true;\n requestId = buildResult.requestId ?? uploadResult.requestId ?? requestId;\n }\n\n if (parsed.options.has('wait')) {\n const waited = await waitForDraft(client, runtime, {\n appId,\n version,\n packageSha256: localPackage.sha256,\n timeoutMs: waitTimeoutSeconds * 1000,\n intervalMs: pollIntervalSeconds * 1000,\n });\n versionId = packageId(waited.item) || versionId;\n requestId = waited.requestId ?? requestId;\n }\n\n const data = {\n appId,\n version,\n versionId,\n filename: localPackage.filename,\n packageSize: localPackage.size,\n packageSha256: localPackage.sha256,\n recovered,\n uploadReplay,\n buildReplay,\n waited: parsed.options.has('wait'),\n };\n if (parsed.json) {\n outputJson(runtime.io, {\n ok: true,\n command: commandName,\n data,\n ...(requestId ? { requestId } : {}),\n });\n } else runtime.io.stdout(renderUploadResult(data));\n return 0;\n }\n\n const lifecycleCommand = LIFECYCLE_COMMANDS[commandName];\n if (lifecycleCommand) {\n const allowedOptions = [\n 'app-id',\n 'version-id',\n 'confirm',\n 'idempotency-key',\n 'wait',\n 'wait-timeout',\n 'poll-interval',\n ...(lifecycleCommand.action === 'review-submit' ? ['auto-publish'] : []),\n ];\n assertOptions(parsed.options, allowedOptions);\n const appId = requiredOption(parsed.options, 'app-id').trim();\n const versionId = requiredOption(parsed.options, 'version-id').trim();\n if (parsed.options.get('confirm') !== true) {\n throw new PhizCliError('Lifecycle writes require the explicit --confirm flag', {\n code: 'CONFIRMATION_REQUIRED',\n });\n }\n if (parsed.options.has('auto-publish') && parsed.options.get('auto-publish') !== true) {\n throw new PhizCliError('--auto-publish is a flag and does not accept a value', {\n code: 'INVALID_ARGUMENT',\n });\n }\n\n const waitTimeoutSeconds = positiveInteger(parsed.options.get('wait-timeout'), 120, 3600);\n const pollIntervalSeconds = positiveInteger(parsed.options.get('poll-interval'), 2, 60);\n const idempotencyKey = resolveLifecycleIdempotencyKey(\n parsed.options.get('idempotency-key'),\n lifecycleCommand.action,\n appId,\n versionId,\n lifecycleCommand.action === 'review-submit'\n ? String(parsed.options.get('auto-publish') === true)\n : ''\n );\n const result = await client.executeVersionLifecycle({\n action: lifecycleCommand.action,\n appId,\n versionId,\n idempotencyKey,\n ...(lifecycleCommand.action === 'review-submit'\n ? { autoPublish: parsed.options.get('auto-publish') === true }\n : {}),\n });\n const state = await queryLifecycleState(client, runtime, {\n appId,\n versionId,\n command: lifecycleCommand,\n wait: parsed.options.get('wait') === true,\n timeoutMs: waitTimeoutSeconds * 1000,\n intervalMs: pollIntervalSeconds * 1000,\n });\n const data = {\n ...result.data,\n action: lifecycleCommand.action,\n appId,\n versionId,\n replayed: result.idempotentReplay === true,\n verified: state.verified,\n status: state.data,\n ...(state.requestId ? { statusRequestId: state.requestId } : {}),\n };\n if (parsed.json) {\n outputJson(runtime.io, {\n ok: true,\n command: commandName,\n data,\n ...(result.requestId ? { requestId: result.requestId } : {}),\n });\n } else runtime.io.stdout(renderLifecycleResult(data));\n return 0;\n }\n\n throw new PhizCliError(`Unknown command: ${commandName}`, { code: 'UNKNOWN_COMMAND' });\n } catch (error) {\n const normalized =\n error instanceof PhizCliError\n ? error\n : new PhizCliError(error instanceof Error ? error.message : 'Unexpected CLI error', {\n code: error instanceof TypeError ? 'CONFIG_INVALID' : 'CLI_ERROR',\n });\n if (jsonRequested) outputJson(runtime.io, errorPayload(normalized));\n else runtime.io.stderr(`${normalized.code}: ${normalized.message}`);\n return ['INVALID_ARGUMENT', 'UNKNOWN_COMMAND', 'CONFIRMATION_REQUIRED'].includes(\n normalized.code\n )\n ? 2\n : 1;\n }\n}\n","import { runCli } from './cli';\n\nconst exitCode = await runCli(process.argv.slice(2), {\n env: process.env,\n io: {\n stdout: (value) => process.stdout.write(`${value}\\n`),\n stderr: (value) => process.stderr.write(`${value}\\n`),\n },\n});\n\nprocess.exitCode = exitCode;\n"]}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "open-phiz-cli",
3
+ "version": "0.1.0",
4
+ "description": "Command-line and CI client for Open Phiz developer APIs",
5
+ "license": "UNLICENSED",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/phiz-clip/open-phiz.git",
9
+ "directory": "packages/open-platform-cli"
10
+ },
11
+ "homepage": "https://github.com/phiz-clip/open-phiz#readme",
12
+ "bugs": "https://github.com/phiz-clip/open-phiz/issues",
13
+ "keywords": [
14
+ "open-phiz",
15
+ "mini-app",
16
+ "cli",
17
+ "ci",
18
+ "release"
19
+ ],
20
+ "type": "module",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
23
+ "bin": {
24
+ "phiz": "./dist/index.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "sideEffects": false,
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "dev": "tsup --watch",
34
+ "test": "bun test src",
35
+ "test:coverage": "bun test --coverage --coverage-reporter=lcov --coverage-dir=coverage src",
36
+ "type-check": "tsc --noEmit",
37
+ "lint": "eslint src",
38
+ "lint:fix": "eslint src --fix",
39
+ "pack:check": "npm pack --dry-run --json",
40
+ "smoke": "node scripts/smoke.mjs",
41
+ "clean": "rm -rf dist"
42
+ },
43
+ "engines": {
44
+ "node": ">=22.12.0"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "provenance": false
49
+ },
50
+ "devDependencies": {
51
+ "@phiz/eslint-config": "workspace:*",
52
+ "@phiz/tsconfig": "workspace:*",
53
+ "@types/node": "^22.20.0",
54
+ "tsup": "^8.5.1",
55
+ "typescript": "^6.0.3"
56
+ }
57
+ }