@privos_ai/app-server 0.8.4 → 0.10.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.
Files changed (70) hide show
  1. package/README.md +76 -1
  2. package/dist/cli/commands/lint.d.ts +8 -0
  3. package/dist/cli/commands/lint.d.ts.map +1 -0
  4. package/dist/cli/commands/lint.js +24 -0
  5. package/dist/cli/commands/lint.js.map +1 -0
  6. package/dist/cli/commands/publish.d.ts +20 -0
  7. package/dist/cli/commands/publish.d.ts.map +1 -0
  8. package/dist/cli/commands/publish.js +365 -0
  9. package/dist/cli/commands/publish.js.map +1 -0
  10. package/dist/cli/index.d.ts +3 -0
  11. package/dist/cli/index.d.ts.map +1 -0
  12. package/dist/cli/index.js +36 -0
  13. package/dist/cli/index.js.map +1 -0
  14. package/dist/cli/lib/authorize.d.ts +80 -0
  15. package/dist/cli/lib/authorize.d.ts.map +1 -0
  16. package/dist/cli/lib/authorize.js +86 -0
  17. package/dist/cli/lib/authorize.js.map +1 -0
  18. package/dist/cli/lib/manifest.d.ts +30 -0
  19. package/dist/cli/lib/manifest.d.ts.map +1 -0
  20. package/dist/cli/lib/manifest.js +61 -0
  21. package/dist/cli/lib/manifest.js.map +1 -0
  22. package/dist/cli/lib/output.d.ts +66 -0
  23. package/dist/cli/lib/output.d.ts.map +1 -0
  24. package/dist/cli/lib/output.js +61 -0
  25. package/dist/cli/lib/output.js.map +1 -0
  26. package/dist/cli/lib/package-source.d.ts +63 -0
  27. package/dist/cli/lib/package-source.d.ts.map +1 -0
  28. package/dist/cli/lib/package-source.js +219 -0
  29. package/dist/cli/lib/package-source.js.map +1 -0
  30. package/dist/cli/lib/portal-client.d.ts +38 -0
  31. package/dist/cli/lib/portal-client.d.ts.map +1 -0
  32. package/dist/cli/lib/portal-client.js +87 -0
  33. package/dist/cli/lib/portal-client.js.map +1 -0
  34. package/dist/cli/lib/upload.d.ts +54 -0
  35. package/dist/cli/lib/upload.d.ts.map +1 -0
  36. package/dist/cli/lib/upload.js +75 -0
  37. package/dist/cli/lib/upload.js.map +1 -0
  38. package/dist/index.d.ts +6 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +2 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/manifest-lint-cli.js +5 -16
  43. package/dist/manifest-lint-cli.js.map +1 -1
  44. package/dist/relay/relay-client.d.ts.map +1 -1
  45. package/dist/relay/relay-client.js +25 -5
  46. package/dist/relay/relay-client.js.map +1 -1
  47. package/dist/runtime.d.ts +38 -0
  48. package/dist/runtime.d.ts.map +1 -1
  49. package/dist/runtime.js +92 -5
  50. package/dist/runtime.js.map +1 -1
  51. package/dist/ui/asset-filename-rule.d.ts +18 -0
  52. package/dist/ui/asset-filename-rule.d.ts.map +1 -0
  53. package/dist/ui/asset-filename-rule.js +39 -0
  54. package/dist/ui/asset-filename-rule.js.map +1 -0
  55. package/dist/ui/assets-manifest.d.ts +19 -0
  56. package/dist/ui/assets-manifest.d.ts.map +1 -0
  57. package/dist/ui/assets-manifest.js +128 -0
  58. package/dist/ui/assets-manifest.js.map +1 -0
  59. package/dist/ui/serve-built-ui.d.ts +28 -0
  60. package/dist/ui/serve-built-ui.d.ts.map +1 -0
  61. package/dist/ui/serve-built-ui.js +131 -0
  62. package/dist/ui/serve-built-ui.js.map +1 -0
  63. package/dist/ui/shell-watchdog.d.ts +12 -0
  64. package/dist/ui/shell-watchdog.d.ts.map +1 -0
  65. package/dist/ui/shell-watchdog.js +25 -0
  66. package/dist/ui/shell-watchdog.js.map +1 -0
  67. package/package.json +3 -1
  68. package/skill/README.md +14 -0
  69. package/skill/SKILL.md +124 -0
  70. package/skill/references/errors.md +68 -0
package/README.md CHANGED
@@ -463,16 +463,91 @@ it is delivered live or the app is re-paired — this is expected, not a bug.
463
463
  `loadStandaloneIdentity` refuses to load a tampered file (wrong mode, foreign
464
464
  owner, or invalid content) with a specific reason instead of degrading silently.
465
465
 
466
+ ## Split-build UI (`serveBuiltUi`)
467
+
468
+ Serve a Vite-built app UI (`base: './'`) over MCP `resources/read` without inlining the whole
469
+ bundle: the shell HTML stays a small resource, and hashed `assets/` files (JS/CSS/fonts/etc) are
470
+ served individually so a Hub can cache them by content hash instead of refetching the entire
471
+ bundle on every open.
472
+
473
+ ```ts
474
+ import { serveBuiltUi } from '@privos_ai/app-server';
475
+
476
+ const appSlug = 'ai.privos.demo';
477
+ const shell = serveBuiltUi({ distDir: './dist/ui', appSlug });
478
+
479
+ const ui = {
480
+ uri: `ui://${appSlug}/form.html`,
481
+ renderHtml: () => shell.renderHtml(),
482
+ readAsset: (uri: string) => shell.readAsset(uri),
483
+ readAssetsManifest: () => shell.readAssetsManifest(),
484
+ };
485
+ ```
486
+
487
+ `serveBuiltUi({ distDir, appSlug })` reads `distDir/index.html` once at construction, injects the
488
+ opt-in `<meta name="privos-ui-assets" content="relay">` tag (if not already present) plus an
489
+ inline boot watchdog `<script>`, and throws immediately if any `<script src>`/`<link href>` is not
490
+ relative (`./assets/…` or `assets/…`) — a sure sign the app was built without Vite `base: './'`.
491
+ It also validates every file under `distDir/assets` at construction: each name must match
492
+ `MCP_UI_ASSET_FILENAME_RE` (content-hashed, allowlisted extension), be ≤ 2 MB, and no `.map` files
493
+ may be present — a violation throws with the full list of offenders rather than serving a broken
494
+ build. `readAsset(uri)` answers `ui://<appSlug>/assets/<file>` resources (`assetUriPrefix`),
495
+ `readAssetsManifest()` answers the sibling `ui://<appSlug>/assets-manifest.json` resource; both are
496
+ wired automatically once `UiResourceProvider.readAsset` / `readAssetsManifest` are set — see
497
+ `runtime.ts`'s `resources/read` handling.
498
+
499
+ `MCP_UI_ASSET_FILENAME_RE`, `MCP_UI_ASSET_EXTENSIONS`, and `deriveAssetUriPrefix(appSlug)` are
500
+ exported for callers that need to validate or derive asset identifiers outside `serveBuiltUi`
501
+ itself.
502
+
466
503
  ## Manifest v2 preflight
467
504
 
468
505
  ```bash
469
506
  npx privos-app-lint ./privos-app.json
507
+ # equivalent to:
508
+ npx privos-app lint ./privos-app.json
470
509
  ```
471
510
 
472
511
  The command rejects mixed legacy/v2 permission declarations and prints deterministic
473
512
  `canonicalManifestHash` and `publisherPermissionDeclarationHash` values. The latter covers the
474
513
  publisher declaration only; Hub/Portal compute the authoritative permission contract hash with
475
- the versioned server-owned catalog and immutable image digest.
514
+ the versioned server-owned catalog and immutable image digest. `privos-app-lint` is kept as a
515
+ compatibility alias for `privos-app lint` — same output, same exit code.
516
+
517
+ ## CLI: `privos-app publish`
518
+
519
+ Run from inside the app folder (where `privos-app.json` and `package.json` live):
520
+
521
+ ```bash
522
+ npx privos-app publish
523
+ ```
524
+
525
+ This packages the git worktree into a source archive (`git archive`, with the same
526
+ dirty-tree refusal, credential-file scan, and entry-policy checks as
527
+ `scripts/package-source.sh`), authorizes with the Portal, uploads the archive, creates
528
+ the version, and submits it for review — in one command, no hand-minted session.
529
+
530
+ Two authorization modes, both ending in a scoped, short-lived Portal grant (never a
531
+ browser session):
532
+
533
+ - **Browser approval (default).** The CLI prints a URL and a user code; approve on
534
+ `client.privos.io` and the CLI proceeds automatically once approved.
535
+ - **Publisher token (CI).** Set `PRIVOS_PUBLISHER_TOKEN` (or pass `--token-stdin`) to
536
+ skip the browser step — only works once the listing's first version was approved
537
+ interactively (`409 LISTING_NOT_BOUND` otherwise).
538
+
539
+ Useful flags: `--listing <slug>`, `--changelog <text>` / `--changelog-file <path>`,
540
+ `--allow-dirty`, `--dry-run` (package only, prints the git revision + archive sha256),
541
+ `--yes` (skip the confirmation prompt), `--portal <origin>`, `--machine-label <text>`,
542
+ `--open` (open the approval URL), `--json` (one NDJSON event per step), `--cwd <path>`.
543
+
544
+ Exit codes: `0` submitted, `2` blocked by policy (lint/package/semver/preflight
545
+ failed/unbound listing), `3` authorization denied/expired, `4` network/portal error,
546
+ `5` usage. The CLI's own manifest lint is structure-only — its
547
+ `canonicalManifestHash` is **not** the Portal's canonical digest and is never sent;
548
+ the Portal returns the authoritative `manifestDigest` after upload. Secrets are never
549
+ printed in full: publisher tokens are shown masked to a prefix, and the publish grant
550
+ value is never printed.
476
551
 
477
552
  ## Scripts
478
553
 
@@ -0,0 +1,8 @@
1
+ /**
2
+ * `privos-app lint [manifestPath]` — identical behavior to the original
3
+ * `privos-app-lint` binary (byte-identical stdout/stderr and exit code).
4
+ * `src/manifest-lint-cli.ts` delegates here so the compatibility alias never
5
+ * drifts from this implementation.
6
+ */
7
+ export declare function runLint(argv: readonly string[]): number;
8
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/lint.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAavD"}
@@ -0,0 +1,24 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { lintManifest } from '../../manifest-tools.js';
4
+ /**
5
+ * `privos-app lint [manifestPath]` — identical behavior to the original
6
+ * `privos-app-lint` binary (byte-identical stdout/stderr and exit code).
7
+ * `src/manifest-lint-cli.ts` delegates here so the compatibility alias never
8
+ * drifts from this implementation.
9
+ */
10
+ export function runLint(argv) {
11
+ const manifestPath = path.resolve(argv[0] || 'privos-app.json');
12
+ let manifest;
13
+ try {
14
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
15
+ }
16
+ catch {
17
+ console.error(JSON.stringify({ valid: false, errors: [`Unable to read valid JSON from ${manifestPath}`] }, null, 2));
18
+ return 1;
19
+ }
20
+ const result = lintManifest(manifest);
21
+ console.log(JSON.stringify({ manifestPath, ...result }, null, 2));
22
+ return result.valid ? 0 : 1;
23
+ }
24
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../../src/cli/commands/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,IAAuB;IAC9C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,iBAAiB,CAAC,CAAC;IAChE,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QACJ,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,kCAAkC,YAAY,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACrH,OAAO,CAAC,CAAC;IACV,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,20 @@
1
+ export type PublishRuntimeOptions = Readonly<{
2
+ env?: NodeJS.ProcessEnv;
3
+ cwd?: string;
4
+ fetchImpl?: typeof fetch;
5
+ sleepImpl?: (ms: number) => Promise<void>;
6
+ openBrowser?: (url: string) => void;
7
+ readTokenFromStdin?: () => Promise<string>;
8
+ confirm?: (question: string) => Promise<boolean>;
9
+ isTTY?: boolean;
10
+ cliVersion?: string;
11
+ }>;
12
+ /**
13
+ * `privos-app publish` — package → lint (structure only) → authorize
14
+ * (browser device flow or `PRIVOS_PUBLISHER_TOKEN`) → upload → version →
15
+ * submit. See phase-04 requirements for the exact sequencing and exit codes
16
+ * (0 submitted, 2 blocked by policy, 3 authorization denied/expired, 4
17
+ * network/portal error, 5 usage).
18
+ */
19
+ export declare function runPublish(argv: readonly string[], runtime?: PublishRuntimeOptions): Promise<number>;
20
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/publish.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,SAAS,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC,CAAC;AAUH;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAiL9G"}
@@ -0,0 +1,365 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import readline from 'node:readline/promises';
4
+ import { parseArgs } from 'node:util';
5
+ import { spawn } from 'node:child_process';
6
+ import { loadManifest, loadPackageJson, assertIdentityAgreement, structuralLint, ManifestLoadError } from '../lib/manifest.js';
7
+ import { packageSource, PackagePolicyError } from '../lib/package-source.js';
8
+ import { PortalClient, PortalError } from '../lib/portal-client.js';
9
+ import { createAuthorization, waitForApproval } from '../lib/authorize.js';
10
+ import { createUploadSession, uploadPartsSequentially, completeUpload, createVersion, submitVersion, waitForPreflight, DEFAULT_PART_SIZE_BYTES, } from '../lib/upload.js';
11
+ import { Reporter, maskSecret } from '../lib/output.js';
12
+ const DEFAULT_PORTAL_ORIGIN = 'https://portal.privos.io';
13
+ /** Internal control-flow error carrying the CLI exit code to return. */
14
+ class CliExitError extends Error {
15
+ exitCode;
16
+ code;
17
+ constructor(message, exitCode, code) {
18
+ super(message);
19
+ this.exitCode = exitCode;
20
+ this.code = code;
21
+ this.name = 'CliExitError';
22
+ }
23
+ }
24
+ /**
25
+ * `privos-app publish` — package → lint (structure only) → authorize
26
+ * (browser device flow or `PRIVOS_PUBLISHER_TOKEN`) → upload → version →
27
+ * submit. See phase-04 requirements for the exact sequencing and exit codes
28
+ * (0 submitted, 2 blocked by policy, 3 authorization denied/expired, 4
29
+ * network/portal error, 5 usage).
30
+ */
31
+ export async function runPublish(argv, runtime = {}) {
32
+ const env = runtime.env ?? process.env;
33
+ let values;
34
+ try {
35
+ ({ values } = parseArgs({
36
+ args: argv,
37
+ options: {
38
+ listing: { type: 'string' },
39
+ changelog: { type: 'string' },
40
+ 'changelog-file': { type: 'string' },
41
+ 'allow-dirty': { type: 'boolean', default: false },
42
+ 'dry-run': { type: 'boolean', default: false },
43
+ yes: { type: 'boolean', default: false },
44
+ portal: { type: 'string' },
45
+ 'machine-label': { type: 'string' },
46
+ open: { type: 'boolean', default: false },
47
+ json: { type: 'boolean', default: false },
48
+ cwd: { type: 'string' },
49
+ 'token-stdin': { type: 'boolean', default: false },
50
+ help: { type: 'boolean', default: false, short: 'h' },
51
+ },
52
+ allowPositionals: false,
53
+ }));
54
+ }
55
+ catch (error) {
56
+ console.error(error instanceof Error ? error.message : String(error));
57
+ return 5;
58
+ }
59
+ if (values.help) {
60
+ printPublishUsage();
61
+ return 0;
62
+ }
63
+ const jsonMode = Boolean(values.json);
64
+ const reporter = new Reporter(jsonMode);
65
+ const cwd = path.resolve(runtime.cwd ?? (typeof values.cwd === 'string' ? values.cwd : process.cwd()));
66
+ try {
67
+ // Step 1: locate + validate manifest identity (structure only — never send this hash to the Portal).
68
+ const { manifestPath, manifest } = loadManifest(cwd);
69
+ const { pkg } = loadPackageJson(cwd);
70
+ const lintResult = structuralLint(manifest);
71
+ if (!lintResult.valid) {
72
+ reporter.emit({ event: 'lint', ok: false, manifestPath });
73
+ throw new CliExitError(`Manifest is invalid:\n- ${lintResult.errors.join('\n- ')}`, 2, 'MANIFEST_INVALID');
74
+ }
75
+ const identityErrors = assertIdentityAgreement(manifest, pkg);
76
+ if (identityErrors.length > 0) {
77
+ reporter.emit({ event: 'lint', ok: false, manifestPath });
78
+ throw new CliExitError(identityErrors.join('\n'), 2, 'MANIFEST_IDENTITY_MISMATCH');
79
+ }
80
+ reporter.emit({ event: 'lint', ok: true, manifestPath });
81
+ const name = String(manifest.name);
82
+ const version = String(manifest.version);
83
+ // Step 2: package (refuse dirty tree unless --allow-dirty; entry policy enforced inside).
84
+ const packaged = packageOrThrow(cwd, name, version, Boolean(values['allow-dirty']));
85
+ reporter.emit({
86
+ event: 'package',
87
+ archivePath: packaged.archivePath,
88
+ bytes: packaged.bytes,
89
+ sha256: packaged.sha256,
90
+ entryCount: packaged.entries.length,
91
+ });
92
+ if (values['dry-run']) {
93
+ reporter.emit({ event: 'status', state: 'DRY_RUN', message: `git ${packaged.gitRevision} · sha256:${packaged.sha256}` });
94
+ return 0;
95
+ }
96
+ // Step 3: resolve config + credentials.
97
+ const changelog = resolveChangelog(values, cwd);
98
+ const portalOrigin = typeof values.portal === 'string' ? values.portal : env.PRIVOS_PORTAL_ORIGIN || DEFAULT_PORTAL_ORIGIN;
99
+ const cliVersion = runtime.cliVersion ?? getOwnPackageVersion();
100
+ const token = values['token-stdin']
101
+ ? (await (runtime.readTokenFromStdin ?? readTokenFromStdin)()).trim()
102
+ : env.PRIVOS_PUBLISHER_TOKEN || undefined;
103
+ if (token)
104
+ reporter.emit({ event: 'authorization_token', maskedToken: maskSecret(token) });
105
+ if (!values.yes && !jsonMode && (runtime.isTTY ?? Boolean(process.stdin.isTTY))) {
106
+ const confirm = runtime.confirm ?? defaultConfirm;
107
+ const proceed = await confirm(`Publish ${name}@${version} (sha256:${packaged.sha256.slice(0, 12)}…)? [y/N] `);
108
+ if (!proceed)
109
+ throw new CliExitError('Publish cancelled.', 5, 'CANCELLED');
110
+ }
111
+ const client = new PortalClient({ origin: portalOrigin, fetchImpl: runtime.fetchImpl, sleepImpl: runtime.sleepImpl });
112
+ // Step 4: authorize — browser device flow (default) or publisher-token auto-approve (CI).
113
+ const { grant, listing } = await authorize(client, runtime, reporter, token, {
114
+ manifestName: name,
115
+ semver: version,
116
+ archiveSha256: packaged.sha256,
117
+ archiveBytes: packaged.bytes,
118
+ cliVersion,
119
+ listingSlug: typeof values.listing === 'string' ? values.listing : undefined,
120
+ machineLabel: typeof values['machine-label'] === 'string' ? values['machine-label'] : undefined,
121
+ open: Boolean(values.open),
122
+ });
123
+ reporter.emit({ event: 'authorization_approved', listingId: listing.id, listingSlug: listing.slug });
124
+ // Step 5: upload sequentially under the grant.
125
+ const archiveBuffer = fs.readFileSync(packaged.archivePath);
126
+ let uploadId;
127
+ try {
128
+ ({ uploadId } = await createUploadSession(client, grant.value, listing.id, {
129
+ fileName: path.basename(packaged.archivePath),
130
+ totalBytes: archiveBuffer.length,
131
+ paths: packaged.filePaths,
132
+ }));
133
+ await uploadPartsSequentially(client, grant.value, uploadId, archiveBuffer, DEFAULT_PART_SIZE_BYTES, (part, totalParts) => reporter.emit({ event: 'upload_progress', part, totalParts }));
134
+ }
135
+ catch (error) {
136
+ throw mapGrantPortalError(error);
137
+ }
138
+ // Step 6: complete — verify + print the Portal's canonical digest.
139
+ let manifestDigest;
140
+ try {
141
+ const completed = await completeUpload(client, grant.value, uploadId);
142
+ manifestDigest = completed.manifestDigest;
143
+ reporter.emit({ event: 'upload_complete', sha256: completed.sha256, manifestDigest });
144
+ }
145
+ catch (error) {
146
+ throw mapGrantPortalError(error);
147
+ }
148
+ // Step 7: version.
149
+ let createdVersion;
150
+ try {
151
+ createdVersion = await createVersion(client, grant.value, listing.id, { semver: version, uploadId, changelog });
152
+ }
153
+ catch (error) {
154
+ throw mapGrantPortalError(error);
155
+ }
156
+ reporter.emit({ event: 'version_created', versionId: createdVersion.id, semver: createdVersion.semver });
157
+ // Step 8: submit, then wait ≤60s for preflight to leave PENDING.
158
+ try {
159
+ await submitVersion(client, grant.value, listing.id, createdVersion.id);
160
+ }
161
+ catch (error) {
162
+ throw mapGrantPortalError(error);
163
+ }
164
+ reporter.emit({ event: 'submitted', versionId: createdVersion.id });
165
+ const finalVersion = await waitForPreflight(client, grant.value, listing.id, createdVersion.id, { sleepImpl: runtime.sleepImpl });
166
+ const finalState = finalVersion?.state ?? 'PREFLIGHT_PENDING';
167
+ if (finalState === 'PREFLIGHT_FAILED') {
168
+ const findings = JSON.stringify(finalVersion.preflightFindings ?? finalVersion);
169
+ throw new CliExitError(`Preflight failed:\n${findings}`, 2, 'PREFLIGHT_FAILED');
170
+ }
171
+ if (finalState === 'PREFLIGHT_BLOCKED_INFRA') {
172
+ reporter.emit({
173
+ event: 'status',
174
+ state: finalState,
175
+ message: 'blocked on Portal build infrastructure — this is admin-side, not a problem with your submission',
176
+ });
177
+ return 0;
178
+ }
179
+ reporter.emit({ event: 'status', state: finalState, message: 'follow up in Creator Studio' });
180
+ return 0;
181
+ }
182
+ catch (error) {
183
+ if (error instanceof CliExitError) {
184
+ reporter.emit({ event: 'error', code: error.code, message: error.message });
185
+ return error.exitCode;
186
+ }
187
+ if (error instanceof ManifestLoadError) {
188
+ reporter.emit({ event: 'error', message: error.message });
189
+ return 5;
190
+ }
191
+ if (error instanceof PortalError) {
192
+ reporter.emit({ event: 'error', code: error.code, message: error.message });
193
+ return 4;
194
+ }
195
+ reporter.emit({ event: 'error', message: error instanceof Error ? error.message : String(error) });
196
+ return 4;
197
+ }
198
+ }
199
+ function packageOrThrow(cwd, name, version, allowDirty) {
200
+ try {
201
+ return packageSource({ cwd, name, version, allowDirty });
202
+ }
203
+ catch (error) {
204
+ if (error instanceof PackagePolicyError) {
205
+ const exitCode = error.code === 'NOT_GIT_REPOSITORY' || error.code === 'GIT_ARCHIVE_FAILED' ? 5 : 2;
206
+ const message = error.details.length > 0 ? `${error.message}\n- ${error.details.join('\n- ')}` : error.message;
207
+ throw new CliExitError(message, exitCode, error.code);
208
+ }
209
+ throw error;
210
+ }
211
+ }
212
+ async function authorize(client, runtime, reporter, token, request) {
213
+ try {
214
+ const outcome = await createAuthorization(client, request, token);
215
+ if (outcome.kind === 'grant') {
216
+ return { grant: outcome.grant, listing: outcome.listing };
217
+ }
218
+ reporter.emit({
219
+ event: 'authorization_device',
220
+ verificationUrl: outcome.verificationUrl,
221
+ userCode: outcome.userCode,
222
+ expiresIn: outcome.expiresIn,
223
+ });
224
+ if (request.open) {
225
+ try {
226
+ (runtime.openBrowser ?? openBrowser)(outcome.verificationUrl);
227
+ }
228
+ catch {
229
+ // best-effort only — the printed URL remains the source of truth.
230
+ }
231
+ }
232
+ const pollOutcome = await waitForApproval(client, outcome.deviceCode, {
233
+ intervalMs: outcome.interval * 1000,
234
+ expiresInMs: outcome.expiresIn * 1000,
235
+ sleepImpl: runtime.sleepImpl,
236
+ onPending: (elapsedMs) => reporter.emit({ event: 'authorization_waiting', elapsedMs }),
237
+ });
238
+ if (pollOutcome.state === 'DENIED') {
239
+ reporter.emit({ event: 'authorization_denied' });
240
+ throw new CliExitError('Publish authorization was denied.', 3, 'AUTHORIZATION_DENIED');
241
+ }
242
+ if (pollOutcome.state === 'EXPIRED') {
243
+ reporter.emit({ event: 'authorization_expired' });
244
+ throw new CliExitError('Publish authorization expired; re-run to request a new approval.', 3, 'AUTHORIZATION_EXPIRED');
245
+ }
246
+ if (pollOutcome.state === 'CONSUMED') {
247
+ throw new CliExitError('Publish authorization was already consumed; re-run to request a new approval.', 3, 'AUTHORIZATION_CONSUMED');
248
+ }
249
+ return { grant: pollOutcome.grant, listing: { id: pollOutcome.grant.listingId, slug: pollOutcome.grant.listingSlug } };
250
+ }
251
+ catch (error) {
252
+ if (error instanceof CliExitError)
253
+ throw error;
254
+ if (error instanceof PortalError)
255
+ throw mapAuthorizationPortalError(error);
256
+ throw error;
257
+ }
258
+ }
259
+ function mapAuthorizationPortalError(error) {
260
+ if (error.code === 'LISTING_NOT_BOUND') {
261
+ return new CliExitError('Listing is not yet bound to this manifest — approve the first version of this listing in your browser: run without the token.', 2, error.code);
262
+ }
263
+ if (error.code === 'LISTING_UNRESOLVED') {
264
+ return new CliExitError('Listing could not be resolved — pass --listing <slug> to select it.', 2, error.code);
265
+ }
266
+ // A revoked/expired/invalid publisher token is an authorization denial, not a
267
+ // transport fault — surface it as exit 3 so CI can tell "rotate the token" apart
268
+ // from "the Portal is unreachable".
269
+ if (error.code === 'PUBLISHER_TOKEN_REVOKED' ||
270
+ error.code === 'PUBLISHER_TOKEN_EXPIRED' ||
271
+ error.code === 'PUBLISHER_TOKEN_INVALID') {
272
+ return new CliExitError(`Publisher token rejected (${error.code}); rotate it in Creator Studio.`, 3, error.code);
273
+ }
274
+ return new CliExitError(error.message, 4, error.code);
275
+ }
276
+ function mapGrantPortalError(error) {
277
+ if (!(error instanceof PortalError))
278
+ return error instanceof Error ? error : new Error(String(error));
279
+ if (error.code === 'PUBLISH_GRANT_EXPIRED') {
280
+ return new CliExitError('Publish grant expired mid-upload; re-run to request a new approval.', 3, error.code);
281
+ }
282
+ if (error.code === 'PUBLISH_GRANT_MISMATCH') {
283
+ return new CliExitError('Uploaded archive or manifest does not match the approved authorization; re-run publish from a clean state.', 2, error.code);
284
+ }
285
+ if (error.code === 'VERSION_SEMVER_EXISTS') {
286
+ return new CliExitError('Version already exists — bump `version` in privos-app.json and package.json.', 2, error.code);
287
+ }
288
+ return new CliExitError(error.message, 4, error.code);
289
+ }
290
+ function resolveChangelog(values, cwd) {
291
+ if (typeof values.changelog === 'string')
292
+ return values.changelog;
293
+ if (typeof values['changelog-file'] === 'string') {
294
+ const changelogPath = path.resolve(cwd, values['changelog-file']);
295
+ try {
296
+ return fs.readFileSync(changelogPath, 'utf8').trim();
297
+ }
298
+ catch {
299
+ throw new CliExitError(`Unable to read changelog file: ${changelogPath}`, 5, 'USAGE');
300
+ }
301
+ }
302
+ return '';
303
+ }
304
+ function getOwnPackageVersion() {
305
+ try {
306
+ const packageJsonUrl = new URL('../../../package.json', import.meta.url);
307
+ const pkg = JSON.parse(fs.readFileSync(packageJsonUrl, 'utf8'));
308
+ return typeof pkg.version === 'string' ? pkg.version : '0.0.0';
309
+ }
310
+ catch {
311
+ return '0.0.0';
312
+ }
313
+ }
314
+ async function readTokenFromStdin() {
315
+ const chunks = [];
316
+ for await (const chunk of process.stdin)
317
+ chunks.push(Buffer.from(chunk));
318
+ return Buffer.concat(chunks).toString('utf8');
319
+ }
320
+ async function defaultConfirm(question) {
321
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
322
+ try {
323
+ const answer = await rl.question(question);
324
+ return /^y(es)?$/i.test(answer.trim());
325
+ }
326
+ finally {
327
+ rl.close();
328
+ }
329
+ }
330
+ function openBrowser(url) {
331
+ if (process.platform === 'darwin') {
332
+ spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
333
+ }
334
+ else if (process.platform === 'win32') {
335
+ spawn('cmd', ['/c', 'start', '""', url], { detached: true, stdio: 'ignore' }).unref();
336
+ }
337
+ else {
338
+ spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
339
+ }
340
+ }
341
+ function printPublishUsage() {
342
+ console.log(`Usage: privos-app publish [options]
343
+
344
+ Packages the app in the current directory (or --cwd), authorizes with the
345
+ Portal (browser approval by default, or PRIVOS_PUBLISHER_TOKEN for CI),
346
+ uploads the source archive, creates the version, and submits it for review.
347
+
348
+ Options:
349
+ --listing <slug> Listing slug when it cannot be resolved from the manifest name
350
+ --changelog <text> Changelog text for this version
351
+ --changelog-file <path> Read changelog text from a file
352
+ --allow-dirty Package an uncommitted working tree (git write-tree snapshot)
353
+ --dry-run Package only; print the git revision and archive sha256, then stop
354
+ --yes Skip the interactive confirmation prompt
355
+ --portal <origin> Portal origin (default: $PRIVOS_PORTAL_ORIGIN or https://portal.privos.io)
356
+ --machine-label <text> Label shown on the approval page (never the hostname by default)
357
+ --open Open the approval URL in a browser
358
+ --json Emit one NDJSON event per step
359
+ --cwd <path> Directory containing privos-app.json and package.json
360
+ --token-stdin Read PRIVOS_PUBLISHER_TOKEN from stdin instead of the environment
361
+ -h, --help Show this help
362
+
363
+ Exit codes: 0 submitted, 2 blocked by policy, 3 authorization denied/expired, 4 network/portal error, 5 usage.`);
364
+ }
365
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../../src/cli/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { runLint } from './commands/lint.js';
3
+ import { runPublish } from './commands/publish.js';
4
+ function printUsage() {
5
+ console.log(`Usage: privos-app <command> [options]
6
+
7
+ Commands:
8
+ lint [manifestPath] Validate privos-app.json structure (default: ./privos-app.json)
9
+ publish [options] Package, authorize, upload and submit the app to the Marketplace
10
+
11
+ Run "privos-app publish --help" for publish options.`);
12
+ }
13
+ async function main() {
14
+ const [subcommand, ...rest] = process.argv.slice(2);
15
+ switch (subcommand) {
16
+ case 'lint':
17
+ return runLint(rest);
18
+ case 'publish':
19
+ return runPublish(rest);
20
+ case '-h':
21
+ case '--help':
22
+ printUsage();
23
+ return 0;
24
+ case undefined:
25
+ printUsage();
26
+ return 5;
27
+ default:
28
+ console.error(`Unknown command "${subcommand}". Usage: privos-app <lint|publish> [options]`);
29
+ return 5;
30
+ }
31
+ }
32
+ main().then((exitCode) => process.exit(exitCode), (error) => {
33
+ console.error(error instanceof Error ? error.message : String(error));
34
+ process.exit(4);
35
+ });
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,SAAS,UAAU;IAClB,OAAO,CAAC,GAAG,CAAC;;;;;;qDAMwC,CAAC,CAAC;AACvD,CAAC;AAED,KAAK,UAAU,IAAI;IAClB,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpD,QAAQ,UAAU,EAAE,CAAC;QACpB,KAAK,MAAM;YACV,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;QACtB,KAAK,SAAS;YACb,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;QACzB,KAAK,IAAI,CAAC;QACV,KAAK,QAAQ;YACZ,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,CAAC;QACV,KAAK,SAAS;YACb,UAAU,EAAE,CAAC;YACb,OAAO,CAAC,CAAC;QACV;YACC,OAAO,CAAC,KAAK,CAAC,oBAAoB,UAAU,+CAA+C,CAAC,CAAC;YAC7F,OAAO,CAAC,CAAC;IACX,CAAC;AACF,CAAC;AAED,IAAI,EAAE,CAAC,IAAI,CACV,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EACpC,CAAC,KAAc,EAAE,EAAE;IAClB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CACD,CAAC"}