@serve.zone/appstore 32.27.0 → 33.0.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 (125) hide show
  1. package/.smartconfig.json +4 -1
  2. package/changelog.md +57 -0
  3. package/dist_catalog/catalog.digest +1 -0
  4. package/dist_catalog/catalog.envelope.json +7440 -0
  5. package/{dist_ts_client/data.generated.js → dist_catalog/catalog.json} +6740 -6913
  6. package/dist_ts_client/catalog.d.ts +16 -0
  7. package/dist_ts_client/catalog.js +12 -0
  8. package/dist_ts_client/index.d.ts +3 -1
  9. package/dist_ts_client/index.js +4 -2
  10. package/dist_ts_client/loader.d.ts +69 -0
  11. package/dist_ts_client/loader.js +361 -0
  12. package/dist_ts_client/plugins.d.ts +5 -0
  13. package/dist_ts_client/plugins.js +8 -0
  14. package/dist_ts_client/projection.d.ts +59 -0
  15. package/dist_ts_client/projection.js +83 -0
  16. package/dist_ts_client/storage.d.ts +15 -9
  17. package/dist_ts_client/storage.js +81 -657
  18. package/dist_ts_client/types.d.ts +86 -41
  19. package/dist_ts_client/types.js +1 -1
  20. package/dist_ts_testing/fixtures.d.ts +83 -0
  21. package/dist_ts_testing/fixtures.js +146 -0
  22. package/dist_ts_testing/index.d.ts +1 -0
  23. package/dist_ts_testing/index.js +2 -0
  24. package/dist_ts_testing/plugins.d.ts +7 -0
  25. package/dist_ts_testing/plugins.js +11 -0
  26. package/package.json +15 -10
  27. package/readme.md +161 -92
  28. package/ts_client/catalog.ts +26 -0
  29. package/ts_client/index.ts +3 -1
  30. package/ts_client/loader.ts +414 -0
  31. package/ts_client/plugins.ts +10 -0
  32. package/ts_client/projection.ts +148 -0
  33. package/ts_client/readme.md +17 -27
  34. package/ts_client/storage.ts +93 -882
  35. package/ts_client/types.ts +102 -42
  36. package/ts_testing/fixtures.ts +230 -0
  37. package/ts_testing/index.ts +1 -0
  38. package/ts_testing/plugins.ts +15 -0
  39. package/ts_testing/tspublish.json +3 -0
  40. package/apps/adminer/app.json +0 -10
  41. package/apps/adminer/versions/1.0.0/config.json +0 -6
  42. package/apps/cloudly/app.json +0 -14
  43. package/apps/cloudly/versions/1.0.0/config.json +0 -120
  44. package/apps/cloudly/versions/1.1.0/config.json +0 -120
  45. package/apps/cloudly/versions/1.1.1/config.json +0 -120
  46. package/apps/cloudly/versions/1.1.10/config.json +0 -173
  47. package/apps/cloudly/versions/1.1.2/config.json +0 -130
  48. package/apps/cloudly/versions/1.1.3/config.json +0 -130
  49. package/apps/cloudly/versions/1.1.4/config.json +0 -130
  50. package/apps/cloudly/versions/1.1.5/config.json +0 -149
  51. package/apps/cloudly/versions/1.1.6/config.json +0 -149
  52. package/apps/cloudly/versions/1.1.7/config.json +0 -149
  53. package/apps/cloudly/versions/1.1.8/config.json +0 -173
  54. package/apps/cloudly/versions/1.1.9/config.json +0 -173
  55. package/apps/cloudly/versions/1.10.0/config.json +0 -173
  56. package/apps/cloudly/versions/1.11.0/config.json +0 -173
  57. package/apps/cloudly/versions/1.12.0/config.json +0 -173
  58. package/apps/cloudly/versions/1.13.0/config.json +0 -173
  59. package/apps/cloudly/versions/1.14.0/config.json +0 -173
  60. package/apps/cloudly/versions/1.15.0/config.json +0 -173
  61. package/apps/cloudly/versions/1.16.0/config.json +0 -173
  62. package/apps/cloudly/versions/1.17.0/config.json +0 -173
  63. package/apps/cloudly/versions/1.18.0/config.json +0 -173
  64. package/apps/cloudly/versions/1.19.0/config.json +0 -173
  65. package/apps/cloudly/versions/1.2.0/config.json +0 -173
  66. package/apps/cloudly/versions/1.2.1/config.json +0 -173
  67. package/apps/cloudly/versions/1.20.0/config.json +0 -173
  68. package/apps/cloudly/versions/1.21.0/config.json +0 -173
  69. package/apps/cloudly/versions/1.22.0/config.json +0 -173
  70. package/apps/cloudly/versions/1.23.0/config.json +0 -173
  71. package/apps/cloudly/versions/1.24.0/config.json +0 -173
  72. package/apps/cloudly/versions/1.25.0/config.json +0 -173
  73. package/apps/cloudly/versions/1.26.0/config.json +0 -173
  74. package/apps/cloudly/versions/1.27.0/config.json +0 -173
  75. package/apps/cloudly/versions/1.3.0/config.json +0 -173
  76. package/apps/cloudly/versions/1.4.0/config.json +0 -173
  77. package/apps/cloudly/versions/1.5.0/config.json +0 -173
  78. package/apps/cloudly/versions/1.6.0/config.json +0 -173
  79. package/apps/cloudly/versions/1.7.0/config.json +0 -173
  80. package/apps/cloudly/versions/1.8.0/config.json +0 -173
  81. package/apps/cloudly/versions/1.9.0/config.json +0 -173
  82. package/apps/ghost/app.json +0 -10
  83. package/apps/ghost/versions/1.0.0/config.json +0 -18
  84. package/apps/gitea/app.json +0 -10
  85. package/apps/gitea/versions/1.0.0/config.json +0 -16
  86. package/apps/gitops/app.json +0 -14
  87. package/apps/gitops/versions/1.0.0/config.json +0 -28
  88. package/apps/grafana/app.json +0 -10
  89. package/apps/grafana/versions/1.0.0/config.json +0 -9
  90. package/apps/mariadb/app.json +0 -10
  91. package/apps/mariadb/versions/1.0.0/config.json +0 -9
  92. package/apps/mattermost/app.json +0 -10
  93. package/apps/mattermost/versions/1.0.0/config.json +0 -6
  94. package/apps/n8n/app.json +0 -10
  95. package/apps/n8n/versions/1.0.0/config.json +0 -6
  96. package/apps/nextcloud/app.json +0 -10
  97. package/apps/nextcloud/versions/1.0.0/config.json +0 -16
  98. package/apps/nginx/app.json +0 -10
  99. package/apps/nginx/versions/1.0.0/config.json +0 -6
  100. package/apps/openbao/app.json +0 -16
  101. package/apps/openbao/versions/1.0.0/config.json +0 -52
  102. package/apps/plausible/app.json +0 -10
  103. package/apps/plausible/versions/1.0.0/config.json +0 -9
  104. package/apps/portainer/app.json +0 -10
  105. package/apps/portainer/versions/1.0.0/config.json +0 -6
  106. package/apps/postgres/app.json +0 -10
  107. package/apps/postgres/versions/1.0.0/config.json +0 -11
  108. package/apps/rustdesk-server/app.json +0 -14
  109. package/apps/rustdesk-server/versions/1.0.0/config.json +0 -19
  110. package/apps/siprouter/app.json +0 -14
  111. package/apps/siprouter/versions/1.0.0/config.json +0 -84
  112. package/apps/uptime-kuma/app.json +0 -10
  113. package/apps/uptime-kuma/versions/1.0.0/config.json +0 -6
  114. package/apps/valkey/app.json +0 -10
  115. package/apps/valkey/versions/1.0.0/config.json +0 -6
  116. package/apps/vaultwarden/app.json +0 -10
  117. package/apps/vaultwarden/versions/1.0.0/config.json +0 -6
  118. package/apps/wordpress/app.json +0 -10
  119. package/apps/wordpress/versions/1.0.0/config.json +0 -15
  120. package/appstore.json +0 -194
  121. package/dist_ts_client/classes.appstoreresolver.d.ts +0 -59
  122. package/dist_ts_client/classes.appstoreresolver.js +0 -736
  123. package/dist_ts_client/data.generated.d.ts +0 -2
  124. package/ts_client/classes.appstoreresolver.ts +0 -896
  125. package/ts_client/data.generated.ts +0 -7606
@@ -0,0 +1,16 @@
1
+ import type * as plugins from './plugins.js';
2
+ type TCatalog = plugins.servezoneInterfaces.appstore.IAppStoreCatalog;
3
+ type TCatalogApp = plugins.servezoneInterfaces.appstore.IAppStoreCatalogApp;
4
+ type TCatalogVersion = plugins.servezoneInterfaces.appstore.IAppStoreCatalogVersion;
5
+ /** The npm package that carries the signed App Store catalog. */
6
+ export declare const appStoreCatalogPackageName = "@serve.zone/appstore";
7
+ /** Where the signed envelope sits inside the published package (and its `./catalog.envelope.json` export). */
8
+ export declare const appStoreCatalogEnvelopePackagePath = "dist_catalog/catalog.envelope.json";
9
+ /** The app a catalog lists under `appIdArg`. */
10
+ export declare const findAppStoreCatalogApp: (catalogArg: TCatalog, appIdArg: string) => TCatalogApp | undefined;
11
+ /**
12
+ * The listed `app@version`, withdrawn ones included: an installed service keeps reading its
13
+ * version. Whether it is an install or upgrade target is `appstore.judgeAppStoreCatalogInstallTarget`.
14
+ */
15
+ export declare const findAppStoreCatalogVersion: (catalogArg: TCatalog, appIdArg: string, versionArg: string) => TCatalogVersion | undefined;
16
+ export {};
@@ -0,0 +1,12 @@
1
+ /** The npm package that carries the signed App Store catalog. */
2
+ export const appStoreCatalogPackageName = '@serve.zone/appstore';
3
+ /** Where the signed envelope sits inside the published package (and its `./catalog.envelope.json` export). */
4
+ export const appStoreCatalogEnvelopePackagePath = 'dist_catalog/catalog.envelope.json';
5
+ /** The app a catalog lists under `appIdArg`. */
6
+ export const findAppStoreCatalogApp = (catalogArg, appIdArg) => catalogArg.apps.find((appArg) => appArg.info.id === appIdArg);
7
+ /**
8
+ * The listed `app@version`, withdrawn ones included: an installed service keeps reading its
9
+ * version. Whether it is an install or upgrade target is `appstore.judgeAppStoreCatalogInstallTarget`.
10
+ */
11
+ export const findAppStoreCatalogVersion = (catalogArg, appIdArg, versionArg) => findAppStoreCatalogApp(catalogArg, appIdArg)?.versions.find((entryArg) => entryArg.version === versionArg);
12
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2F0YWxvZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX2NsaWVudC9jYXRhbG9nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQU1BLGlFQUFpRTtBQUNqRSxNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxzQkFBc0IsQ0FBQztBQUVqRSw4R0FBOEc7QUFDOUcsTUFBTSxDQUFDLE1BQU0sa0NBQWtDLEdBQUcsb0NBQW9DLENBQUM7QUFFdkYsZ0RBQWdEO0FBQ2hELE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLENBQUMsVUFBb0IsRUFBRSxRQUFnQixFQUEyQixFQUFFLENBQ3hHLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxRQUFRLENBQUMsQ0FBQztBQUVoRTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSwwQkFBMEIsR0FBRyxDQUN4QyxVQUFvQixFQUNwQixRQUFnQixFQUNoQixVQUFrQixFQUNXLEVBQUUsQ0FDL0Isc0JBQXNCLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEtBQUssVUFBVSxDQUFDLENBQUMifQ==
@@ -1,3 +1,5 @@
1
- export * from './classes.appstoreresolver.js';
1
+ export * from './catalog.js';
2
+ export * from './loader.js';
3
+ export * from './projection.js';
2
4
  export * from './storage.js';
3
5
  export * from './types.js';
@@ -1,4 +1,6 @@
1
- export * from './classes.appstoreresolver.js';
1
+ export * from './catalog.js';
2
+ export * from './loader.js';
3
+ export * from './projection.js';
2
4
  export * from './storage.js';
3
5
  export * from './types.js';
4
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90c19jbGllbnQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLFlBQVksQ0FBQyJ9
6
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19jbGllbnQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLFlBQVksQ0FBQyJ9
@@ -0,0 +1,69 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { IAppStoreCatalogLoadOptions, IAppStoreCatalogLoaderOptions, IAppStoreCatalogStoredRecord, TAppStoreCatalogJudgement, TAppStoreCatalogLoadResult, TAppStoreCatalogRestoreResult } from './types.js';
3
+ type TEnvelope = plugins.servezoneInterfaces.appstore.IAppStoreCatalogEnvelope;
4
+ /**
5
+ * Loads the signed App Store catalog from npm registries and judges it against the consumer's
6
+ * active catalog. It holds the consumer's options only: no timer, no schedule, no catalog.
7
+ *
8
+ * One load asks every configured registry for the package its `latest` dist-tag names, downloads
9
+ * the tarball, checks it against the registry's `dist.integrity`, extracts the envelope, verifies
10
+ * it against the trusted keys (`verifyAppStoreCatalogEnvelope`) and judges its succession
11
+ * (`judgeAppStoreCatalogSuccession`). The first registry whose catalog activates ends the load;
12
+ * otherwise the result is the first `unchanged`, else the first `refused`, else `failed`, and
13
+ * `registries` reports what each registry answered.
14
+ *
15
+ * The loader holds no state, runs no schedule and persists nothing: the consumer's catalog runtime
16
+ * owns the one refresh schedule of its process, passes its active envelope in, stores an activated
17
+ * one as its last-known-good catalog and restores it with `restoreEnvelopeText` at start. Every
18
+ * request is bounded in time and size; a transport, integrity or packaging failure and every
19
+ * refusal are results, never thrown. Aborting `signal` (the consumer stopping) ends the load at
20
+ * once and rejects it with the signal's reason; no attempt is reported for it.
21
+ */
22
+ export declare class AppStoreCatalogLoader {
23
+ private readonly trustedKeys;
24
+ private readonly supportedFeatureIds;
25
+ private readonly registries;
26
+ private readonly fetchFunction;
27
+ private readonly now;
28
+ private readonly requestTimeoutMs;
29
+ private readonly maximumTarballBytes;
30
+ private readonly maximumUnpackedBytes;
31
+ constructor(optionsArg: IAppStoreCatalogLoaderOptions);
32
+ /** One load from the configured registries; see the class description. */
33
+ loadFromRegistries(activeArg: TEnvelope | null, optionsArg?: IAppStoreCatalogLoadOptions): Promise<TAppStoreCatalogLoadResult>;
34
+ /**
35
+ * Judges an envelope an operator imported (an offline signed bundle, or the envelope a package
36
+ * carries at `./catalog.envelope.json`) exactly as a fetched one: authentication, contract,
37
+ * schema, digests, then succession against the active catalog.
38
+ */
39
+ judgeImportedEnvelope(candidateArg: unknown, activeArg: TEnvelope | null): Promise<TAppStoreCatalogJudgement>;
40
+ /** An envelope read as text: bytes that are not JSON are refused as `schemaInvalid`. */
41
+ judgeImportedEnvelopeText(textArg: string, activeArg: TEnvelope | null): Promise<TAppStoreCatalogJudgement>;
42
+ /**
43
+ * Restores the last-known-good catalog a consumer stored, at start: the stored envelope text is
44
+ * verified again against today's trusted keys and supported features, exactly as a fetched one,
45
+ * and answers the status `active` member it activates (`origin` and `loadedAt` as stored, the
46
+ * verifying key as verified now) or the refusal that keeps it inactive, e.g. `signatureInvalid`
47
+ * once its key is no longer trusted.
48
+ */
49
+ restoreEnvelopeText(textArg: string, recordArg: IAppStoreCatalogStoredRecord): Promise<TAppStoreCatalogRestoreResult>;
50
+ private judgeText;
51
+ /** Envelope text as a value; bytes that are not JSON are a `schemaInvalid` refusal. */
52
+ private parseEnvelopeText;
53
+ private judge;
54
+ /**
55
+ * Authenticates and reads a candidate (`verifyAppStoreCatalogEnvelope`), before and without
56
+ * succession. The verifier answers every refusal as a result; should it throw, the candidate is
57
+ * refused as `schemaInvalid` with the cause, so a load never fails on an input it could not read.
58
+ */
59
+ private verify;
60
+ /** The envelope text the package the registry's `latest` dist-tag names carries. */
61
+ private fetchEnvelopeText;
62
+ /**
63
+ * GET with the request bound covering the response body and a byte bound on the body. The
64
+ * caller's `signalArg` aborts it too; that abort is rethrown as the signal's reason. A redirect is
65
+ * never followed: a registry that answers with one fails, so a request never leaves https.
66
+ */
67
+ private fetchBytes;
68
+ }
69
+ export {};
@@ -0,0 +1,361 @@
1
+ import * as plugins from './plugins.js';
2
+ import { appStoreCatalogEnvelopePackagePath, appStoreCatalogPackageName, } from './catalog.js';
3
+ const defaultRequestTimeoutMs = 30_000;
4
+ const defaultMaximumTarballBytes = 32 * 1024 * 1024;
5
+ const maximumManifestBytes = 1024 * 1024;
6
+ const maximumEnvelopeBytes = 16 * 1024 * 1024;
7
+ const defaultMaximumUnpackedBytes = 256 * 1024 * 1024;
8
+ const envelopeTarballEntryName = `package/${appStoreCatalogEnvelopePackagePath}`;
9
+ /** A failure of the transport, the integrity check or the package layout: no candidate was read. */
10
+ class AppStoreCatalogTransportError extends Error {
11
+ }
12
+ const isRecord = (valueArg) => typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
13
+ const isPositiveSafeInteger = (valueArg) => Number.isSafeInteger(valueArg) && valueArg > 0;
14
+ const toBase64 = (bytesArg) => {
15
+ let binary = '';
16
+ for (const byte of bytesArg)
17
+ binary += String.fromCharCode(byte);
18
+ return btoa(binary);
19
+ };
20
+ /** The `sha512-<base64>` values of an npm `dist.integrity` (Subresource Integrity syntax). */
21
+ const readSha512Integrity = (integrityArg) => integrityArg.split(/\s+/)
22
+ .filter((entryArg) => entryArg.startsWith('sha512-'))
23
+ .map((entryArg) => entryArg.slice('sha512-'.length).replace(/\?.*$/, ''));
24
+ /**
25
+ * Loads the signed App Store catalog from npm registries and judges it against the consumer's
26
+ * active catalog. It holds the consumer's options only: no timer, no schedule, no catalog.
27
+ *
28
+ * One load asks every configured registry for the package its `latest` dist-tag names, downloads
29
+ * the tarball, checks it against the registry's `dist.integrity`, extracts the envelope, verifies
30
+ * it against the trusted keys (`verifyAppStoreCatalogEnvelope`) and judges its succession
31
+ * (`judgeAppStoreCatalogSuccession`). The first registry whose catalog activates ends the load;
32
+ * otherwise the result is the first `unchanged`, else the first `refused`, else `failed`, and
33
+ * `registries` reports what each registry answered.
34
+ *
35
+ * The loader holds no state, runs no schedule and persists nothing: the consumer's catalog runtime
36
+ * owns the one refresh schedule of its process, passes its active envelope in, stores an activated
37
+ * one as its last-known-good catalog and restores it with `restoreEnvelopeText` at start. Every
38
+ * request is bounded in time and size; a transport, integrity or packaging failure and every
39
+ * refusal are results, never thrown. Aborting `signal` (the consumer stopping) ends the load at
40
+ * once and rejects it with the signal's reason; no attempt is reported for it.
41
+ */
42
+ export class AppStoreCatalogLoader {
43
+ trustedKeys;
44
+ supportedFeatureIds;
45
+ registries;
46
+ fetchFunction;
47
+ now;
48
+ requestTimeoutMs;
49
+ maximumTarballBytes;
50
+ maximumUnpackedBytes;
51
+ constructor(optionsArg) {
52
+ if (optionsArg.trustedKeys.length === 0) {
53
+ throw new Error('App Store catalog loader needs at least one trusted key');
54
+ }
55
+ this.trustedKeys = optionsArg.trustedKeys.map((keyArg) => ({ ...keyArg }));
56
+ this.supportedFeatureIds = [...new Set(optionsArg.supportedFeatureIds)].sort();
57
+ this.registries = plugins.servezoneInterfaces.appstore.resolveAppStoreCatalogRegistries(optionsArg.registries);
58
+ this.fetchFunction = optionsArg.fetch ?? ((inputArg, initArg) => fetch(inputArg, initArg));
59
+ this.now = optionsArg.now ?? (() => new Date());
60
+ this.requestTimeoutMs = optionsArg.requestTimeoutMs ?? defaultRequestTimeoutMs;
61
+ this.maximumTarballBytes = optionsArg.maximumTarballBytes ?? defaultMaximumTarballBytes;
62
+ this.maximumUnpackedBytes = optionsArg.maximumUnpackedBytes ?? defaultMaximumUnpackedBytes;
63
+ if (!isPositiveSafeInteger(this.requestTimeoutMs)) {
64
+ throw new Error('App Store catalog requestTimeoutMs must be a positive integer');
65
+ }
66
+ if (!isPositiveSafeInteger(this.maximumTarballBytes)) {
67
+ throw new Error('App Store catalog maximumTarballBytes must be a positive integer');
68
+ }
69
+ if (!isPositiveSafeInteger(this.maximumUnpackedBytes)) {
70
+ throw new Error('App Store catalog maximumUnpackedBytes must be a positive integer');
71
+ }
72
+ }
73
+ /** One load from the configured registries; see the class description. */
74
+ async loadFromRegistries(activeArg, optionsArg = {}) {
75
+ const { signal } = optionsArg;
76
+ const reports = [];
77
+ const judgements = [];
78
+ for (const registry of this.registries) {
79
+ signal?.throwIfAborted();
80
+ try {
81
+ const { packageVersion, envelopeText } = await this.fetchEnvelopeText(registry, signal);
82
+ const judgement = await this.judgeText(envelopeText, activeArg, 'registry');
83
+ judgements.push(judgement);
84
+ reports.push({
85
+ registry,
86
+ outcome: judgement.outcome,
87
+ packageVersion,
88
+ ...(judgement.outcome === 'refused' ? { message: judgement.refused.message } : {}),
89
+ });
90
+ if (judgement.outcome === 'activated')
91
+ break;
92
+ }
93
+ catch (error) {
94
+ signal?.throwIfAborted();
95
+ if (!(error instanceof AppStoreCatalogTransportError))
96
+ throw error;
97
+ reports.push({ registry, outcome: 'failed', message: error.message });
98
+ }
99
+ }
100
+ signal?.throwIfAborted();
101
+ const chosen = judgements.find((judgementArg) => judgementArg.outcome === 'activated')
102
+ ?? judgements.find((judgementArg) => judgementArg.outcome === 'unchanged')
103
+ ?? judgements.find((judgementArg) => judgementArg.outcome === 'refused');
104
+ if (chosen !== undefined)
105
+ return { ...chosen, registries: reports };
106
+ const message = reports.map((reportArg) => `${reportArg.registry}: ${reportArg.message ?? reportArg.outcome}`).join('; ');
107
+ const failure = {
108
+ outcome: 'failed',
109
+ message,
110
+ attempt: { at: this.now().toISOString(), outcome: 'failed', message },
111
+ };
112
+ return { ...failure, registries: reports };
113
+ }
114
+ /**
115
+ * Judges an envelope an operator imported (an offline signed bundle, or the envelope a package
116
+ * carries at `./catalog.envelope.json`) exactly as a fetched one: authentication, contract,
117
+ * schema, digests, then succession against the active catalog.
118
+ */
119
+ async judgeImportedEnvelope(candidateArg, activeArg) {
120
+ return await this.judge(candidateArg, activeArg, 'operatorImport');
121
+ }
122
+ /** An envelope read as text: bytes that are not JSON are refused as `schemaInvalid`. */
123
+ async judgeImportedEnvelopeText(textArg, activeArg) {
124
+ return await this.judgeText(textArg, activeArg, 'operatorImport');
125
+ }
126
+ /**
127
+ * Restores the last-known-good catalog a consumer stored, at start: the stored envelope text is
128
+ * verified again against today's trusted keys and supported features, exactly as a fetched one,
129
+ * and answers the status `active` member it activates (`origin` and `loadedAt` as stored, the
130
+ * verifying key as verified now) or the refusal that keeps it inactive, e.g. `signatureInvalid`
131
+ * once its key is no longer trusted.
132
+ */
133
+ async restoreEnvelopeText(textArg, recordArg) {
134
+ const candidate = this.parseEnvelopeText(textArg);
135
+ const verified = candidate.parsed
136
+ ? await this.verify(candidate.value, recordArg.origin)
137
+ : refuseCandidate(undefined, this.now().toISOString(), candidate.refusal);
138
+ if (verified.outcome === 'refused')
139
+ return verified;
140
+ return {
141
+ outcome: 'restored',
142
+ envelope: verified.envelope,
143
+ active: { ...verified.active, loadedAt: recordArg.loadedAt },
144
+ };
145
+ }
146
+ async judgeText(textArg, activeArg, originArg) {
147
+ const candidate = this.parseEnvelopeText(textArg);
148
+ return candidate.parsed
149
+ ? await this.judge(candidate.value, activeArg, originArg)
150
+ : refuseCandidate(undefined, this.now().toISOString(), candidate.refusal);
151
+ }
152
+ /** Envelope text as a value; bytes that are not JSON are a `schemaInvalid` refusal. */
153
+ parseEnvelopeText(textArg) {
154
+ try {
155
+ return { parsed: true, value: JSON.parse(textArg) };
156
+ }
157
+ catch {
158
+ return { parsed: false, refusal: { reason: 'schemaInvalid', message: 'envelope is not JSON' } };
159
+ }
160
+ }
161
+ async judge(candidateArg, activeArg, originArg) {
162
+ const verified = await this.verify(candidateArg, originArg);
163
+ if (verified.outcome === 'refused')
164
+ return verified;
165
+ const succession = plugins.servezoneInterfaces.appstore.judgeAppStoreCatalogSuccession(activeArg, verified.envelope);
166
+ if (succession.outcome === 'refused')
167
+ return refuseCandidate(candidateArg, verified.attempt.at, succession.refusal);
168
+ if (succession.outcome === 'unchanged') {
169
+ return { outcome: 'unchanged', attempt: { at: verified.attempt.at, outcome: 'unchanged' } };
170
+ }
171
+ return verified;
172
+ }
173
+ /**
174
+ * Authenticates and reads a candidate (`verifyAppStoreCatalogEnvelope`), before and without
175
+ * succession. The verifier answers every refusal as a result; should it throw, the candidate is
176
+ * refused as `schemaInvalid` with the cause, so a load never fails on an input it could not read.
177
+ */
178
+ async verify(candidateArg, originArg) {
179
+ const at = this.now().toISOString();
180
+ let verification;
181
+ try {
182
+ verification = await plugins.servezoneInterfacesRuntime.verifyAppStoreCatalogEnvelope(candidateArg, {
183
+ trustedKeys: this.trustedKeys,
184
+ supportedFeatureIds: this.supportedFeatureIds,
185
+ });
186
+ }
187
+ catch (error) {
188
+ return refuseCandidate(candidateArg, at, {
189
+ reason: 'schemaInvalid',
190
+ message: `envelope could not be verified: ${error instanceof Error ? error.message : String(error)}`,
191
+ });
192
+ }
193
+ if (!verification.accepted)
194
+ return refuseCandidate(candidateArg, at, verification.refusal);
195
+ const { envelope, keyId } = verification;
196
+ const { catalog, catalogDigest } = envelope;
197
+ return {
198
+ outcome: 'activated',
199
+ envelope,
200
+ active: {
201
+ contract: { ...catalog.contract },
202
+ revision: catalog.revision,
203
+ catalogDigest,
204
+ publishedAt: catalog.publishedAt,
205
+ sourceRevision: catalog.sourceRevision,
206
+ loadedAt: at,
207
+ keyId,
208
+ origin: originArg,
209
+ },
210
+ attempt: { at, outcome: 'activated' },
211
+ };
212
+ }
213
+ /** The envelope text the package the registry's `latest` dist-tag names carries. */
214
+ async fetchEnvelopeText(registryArg, signalArg) {
215
+ const manifestUrl = `${registryArg}/${appStoreCatalogPackageName.replace('/', '%2f')}/latest`;
216
+ const manifestBytes = await this.fetchBytes(manifestUrl, maximumManifestBytes, signalArg);
217
+ let manifest;
218
+ try {
219
+ manifest = JSON.parse(new TextDecoder().decode(manifestBytes));
220
+ }
221
+ catch {
222
+ throw new AppStoreCatalogTransportError(`${manifestUrl} did not answer JSON`);
223
+ }
224
+ const dist = isRecord(manifest) ? manifest.dist : undefined;
225
+ if (!isRecord(manifest) || manifest.name !== appStoreCatalogPackageName || typeof manifest.version !== 'string'
226
+ || !isRecord(dist) || typeof dist.tarball !== 'string' || typeof dist.integrity !== 'string') {
227
+ throw new AppStoreCatalogTransportError(`${manifestUrl} is not the ${appStoreCatalogPackageName} version manifest`);
228
+ }
229
+ const packageVersion = manifest.version;
230
+ const expectedSha512 = readSha512Integrity(dist.integrity);
231
+ if (expectedSha512.length === 0) {
232
+ throw new AppStoreCatalogTransportError(`${appStoreCatalogPackageName}@${packageVersion} has no sha512 dist.integrity`);
233
+ }
234
+ let tarballUrl;
235
+ try {
236
+ tarballUrl = new URL(dist.tarball);
237
+ }
238
+ catch {
239
+ throw new AppStoreCatalogTransportError(`${appStoreCatalogPackageName}@${packageVersion} names no tarball URL`);
240
+ }
241
+ if (tarballUrl.protocol !== 'https:' || tarballUrl.username !== '' || tarballUrl.password !== '') {
242
+ throw new AppStoreCatalogTransportError(`${appStoreCatalogPackageName}@${packageVersion} tarball URL must be https without credentials`);
243
+ }
244
+ const tarball = await this.fetchBytes(tarballUrl.toString(), this.maximumTarballBytes, signalArg);
245
+ const actualSha512 = toBase64(new Uint8Array(await crypto.subtle.digest('SHA-512', tarball)));
246
+ if (!expectedSha512.includes(actualSha512)) {
247
+ throw new AppStoreCatalogTransportError(`${appStoreCatalogPackageName}@${packageVersion} tarball does not match its dist.integrity`);
248
+ }
249
+ const envelopeText = await readTarballEntry(tarball, envelopeTarballEntryName, packageVersion, this.maximumUnpackedBytes);
250
+ return { packageVersion, envelopeText };
251
+ }
252
+ /**
253
+ * GET with the request bound covering the response body and a byte bound on the body. The
254
+ * caller's `signalArg` aborts it too; that abort is rethrown as the signal's reason. A redirect is
255
+ * never followed: a registry that answers with one fails, so a request never leaves https.
256
+ */
257
+ async fetchBytes(urlArg, maximumBytesArg, signalArg) {
258
+ const controller = new AbortController();
259
+ const timer = setTimeout(() => controller.abort(), this.requestTimeoutMs);
260
+ const signal = signalArg === undefined ? controller.signal : AbortSignal.any([controller.signal, signalArg]);
261
+ try {
262
+ const response = await this.fetchFunction(urlArg, {
263
+ signal,
264
+ redirect: 'error',
265
+ headers: { accept: 'application/json, application/octet-stream' },
266
+ });
267
+ if (!response.ok) {
268
+ await response.body?.cancel();
269
+ throw new AppStoreCatalogTransportError(`HTTP ${response.status} for ${urlArg}`);
270
+ }
271
+ const declaredLength = Number(response.headers.get('content-length') ?? '0');
272
+ if (declaredLength > maximumBytesArg) {
273
+ await response.body?.cancel();
274
+ throw new AppStoreCatalogTransportError(`${urlArg} exceeds ${maximumBytesArg} bytes`);
275
+ }
276
+ if (response.body === null)
277
+ throw new AppStoreCatalogTransportError(`${urlArg} answered no body`);
278
+ return await readBounded(response.body, maximumBytesArg, urlArg);
279
+ }
280
+ catch (error) {
281
+ signalArg?.throwIfAborted();
282
+ if (controller.signal.aborted) {
283
+ throw new AppStoreCatalogTransportError(`${urlArg} timed out after ${this.requestTimeoutMs} ms`);
284
+ }
285
+ if (error instanceof AppStoreCatalogTransportError)
286
+ throw error;
287
+ throw new AppStoreCatalogTransportError(`${urlArg} failed: ${error instanceof Error ? error.message : String(error)}`);
288
+ }
289
+ finally {
290
+ clearTimeout(timer);
291
+ }
292
+ }
293
+ }
294
+ /** The refusal record and attempt of a candidate, with its revision when it can be read. */
295
+ const refuseCandidate = (candidateArg, atArg, refusalArg) => {
296
+ const revision = readCandidateRevision(candidateArg);
297
+ return {
298
+ outcome: 'refused',
299
+ refused: { ...refusalArg, at: atArg, ...(revision === undefined ? {} : { revision }) },
300
+ attempt: { at: atArg, outcome: 'refused', message: `${refusalArg.reason}: ${refusalArg.message}` },
301
+ };
302
+ };
303
+ const readCandidateRevision = (candidateArg) => {
304
+ const catalog = isRecord(candidateArg) ? candidateArg.catalog : undefined;
305
+ const revision = isRecord(catalog) ? catalog.revision : undefined;
306
+ return typeof revision === 'number' && Number.isSafeInteger(revision) ? revision : undefined;
307
+ };
308
+ const readBounded = async (streamArg, maximumBytesArg, labelArg) => {
309
+ const reader = streamArg.getReader();
310
+ const chunks = [];
311
+ let total = 0;
312
+ try {
313
+ for (;;) {
314
+ const { done, value } = await reader.read();
315
+ if (done)
316
+ break;
317
+ total += value.byteLength;
318
+ if (total > maximumBytesArg) {
319
+ await reader.cancel();
320
+ throw new AppStoreCatalogTransportError(`${labelArg} exceeds ${maximumBytesArg} bytes`);
321
+ }
322
+ chunks.push(value);
323
+ }
324
+ }
325
+ finally {
326
+ reader.releaseLock();
327
+ }
328
+ const bytes = new Uint8Array(total);
329
+ let offset = 0;
330
+ for (const chunk of chunks) {
331
+ bytes.set(chunk, offset);
332
+ offset += chunk.byteLength;
333
+ }
334
+ return bytes;
335
+ };
336
+ /**
337
+ * The text of one regular file in a gzip-compressed npm tarball. The archive is decompressed in
338
+ * full (bounded) before it is decoded: decoding straight from the decompression stream stalls on
339
+ * entries larger than one stream chunk.
340
+ */
341
+ const readTarballEntry = async (tarballArg, entryNameArg, packageVersionArg, maximumUnpackedBytesArg) => {
342
+ const label = `${appStoreCatalogPackageName}@${packageVersionArg}`;
343
+ try {
344
+ const archive = await readBounded(new Blob([tarballArg]).stream().pipeThrough(new DecompressionStream('gzip')), maximumUnpackedBytesArg, `${label} unpacked tarball`);
345
+ const entry = (await plugins.modernTar.unpackTar(archive, { strict: true }))
346
+ .find((entryArg) => entryArg.header.name === entryNameArg && (entryArg.header.type ?? 'file') === 'file');
347
+ if (entry?.data === undefined) {
348
+ throw new AppStoreCatalogTransportError(`${label} carries no ${appStoreCatalogEnvelopePackagePath}`);
349
+ }
350
+ if (entry.data.byteLength > maximumEnvelopeBytes) {
351
+ throw new AppStoreCatalogTransportError(`${label} ${appStoreCatalogEnvelopePackagePath} exceeds ${maximumEnvelopeBytes} bytes`);
352
+ }
353
+ return new TextDecoder().decode(entry.data);
354
+ }
355
+ catch (error) {
356
+ if (error instanceof AppStoreCatalogTransportError)
357
+ throw error;
358
+ throw new AppStoreCatalogTransportError(`${label} tarball could not be read: ${error instanceof Error ? error.message : String(error)}`);
359
+ }
360
+ };
361
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfY2xpZW50L2xvYWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQ0wsa0NBQWtDLEVBQ2xDLDBCQUEwQixHQUMzQixNQUFNLGNBQWMsQ0FBQztBQW1CdEIsTUFBTSx1QkFBdUIsR0FBRyxNQUFNLENBQUM7QUFDdkMsTUFBTSwwQkFBMEIsR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUNwRCxNQUFNLG9CQUFvQixHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDekMsTUFBTSxvQkFBb0IsR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztBQUM5QyxNQUFNLDJCQUEyQixHQUFHLEdBQUcsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQ3RELE1BQU0sd0JBQXdCLEdBQUcsV0FBVyxrQ0FBa0MsRUFBRSxDQUFDO0FBRWpGLG9HQUFvRztBQUNwRyxNQUFNLDZCQUE4QixTQUFRLEtBQUs7Q0FBRztBQUVwRCxNQUFNLFFBQVEsR0FBRyxDQUFDLFFBQWlCLEVBQXVDLEVBQUUsQ0FDMUUsT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLFFBQVEsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWhGLE1BQU0scUJBQXFCLEdBQUcsQ0FBQyxRQUFnQixFQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUM7QUFFNUcsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFvQixFQUFVLEVBQUU7SUFDaEQsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO0lBQ2hCLEtBQUssTUFBTSxJQUFJLElBQUksUUFBUTtRQUFFLE1BQU0sSUFBSSxNQUFNLENBQUMsWUFBWSxD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
@@ -0,0 +1,5 @@
1
+ import * as servezoneInterfaces from '@serve.zone/interfaces';
2
+ import * as servezoneInterfacesRuntime from '@serve.zone/interfaces/runtime';
3
+ export { servezoneInterfaces, servezoneInterfacesRuntime };
4
+ import * as modernTar from 'modern-tar';
5
+ export { modernTar };
@@ -0,0 +1,8 @@
1
+ // @serve.zone scope
2
+ import * as servezoneInterfaces from '@serve.zone/interfaces';
3
+ import * as servezoneInterfacesRuntime from '@serve.zone/interfaces/runtime';
4
+ export { servezoneInterfaces, servezoneInterfacesRuntime };
5
+ // third party
6
+ import * as modernTar from 'modern-tar';
7
+ export { modernTar };
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX2NsaWVudC9wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssbUJBQW1CLE1BQU0sd0JBQXdCLENBQUM7QUFDOUQsT0FBTyxLQUFLLDBCQUEwQixNQUFNLGdDQUFnQyxDQUFDO0FBRTdFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSwwQkFBMEIsRUFBRSxDQUFDO0FBRTNELGNBQWM7QUFDZCxPQUFPLEtBQUssU0FBUyxNQUFNLFlBQVksQ0FBQztBQUV4QyxPQUFPLEVBQUUsU0FBUyxFQUFFLENBQUMifQ==
@@ -0,0 +1,59 @@
1
+ import * as plugins from './plugins.js';
2
+ type TCatalog = plugins.servezoneInterfaces.appstore.IAppStoreCatalog;
3
+ type TCatalogApp = plugins.servezoneInterfaces.appstore.IAppStoreCatalogApp;
4
+ type TAppStoreApp = plugins.servezoneInterfaces.appstore.IAppStoreApp;
5
+ type TAppStoreAppMeta = plugins.servezoneInterfaces.appstore.IAppStoreAppMeta;
6
+ type TVersionState = plugins.servezoneInterfaces.appstore.IAppStoreAppVersionState;
7
+ /** The consumer a projection is for: the feature ids it fulfils, and which host release it is. */
8
+ export interface IAppStoreCatalogProjectionOptions {
9
+ /** The `requiresFeatures` ids this consumer fulfils, e.g. `appStoreStorageFeatureIds` values. */
10
+ supportedFeatureIds: Iterable<string>;
11
+ /** The host and its release, judged against each version's `minOneboxVersion` / `minCloudlyVersion`. */
12
+ consumer: plugins.servezoneInterfaces.appstore.IAppStoreCatalogConsumer;
13
+ }
14
+ /** The App Store shapes Onebox and Cloudly carry in their views and requests for one app. */
15
+ export interface IAppStoreCatalogAppDisplay {
16
+ /** The listing entry (`getAppStoreTemplates`). */
17
+ app: TAppStoreApp;
18
+ /** The app metadata (`getAppStoreConfig`, the upgrade preview). */
19
+ meta: TAppStoreAppMeta;
20
+ }
21
+ /** One catalog app as a consumer with its supported feature ids sees it. */
22
+ export interface IAppStoreCatalogAppProjection {
23
+ appId: string;
24
+ /** The catalog's `latestVersion`, the publisher's latest, whether or not this consumer may install it. */
25
+ catalogLatestVersion: string;
26
+ /**
27
+ * Every listed version in catalog order, withdrawn, feature-gated and newer-release-gated ones
28
+ * included, each with `installRefusal` as `appstore.judgeAppStoreCatalogInstallTarget` answers it.
29
+ */
30
+ versions: TVersionState[];
31
+ /**
32
+ * The newest version this consumer may install, or `null` when none is: every version withdrawn,
33
+ * gated on a feature it does not fulfil or requiring a newer release of it. Under `semver` the highest install target; under
34
+ * `branch` the catalog's `latestVersion` when it is one, since branch tokens have no order.
35
+ */
36
+ latestInstallableVersion: string | null;
37
+ /**
38
+ * The display shapes, or `null` when `latestInstallableVersion` is: their `versions` list only
39
+ * install targets and their `latestVersion` names `latestInstallableVersion`, so a version
40
+ * picker built from them never offers a version the consumer refuses; their `versionStates`
41
+ * state every listed version with its refusal.
42
+ */
43
+ display: IAppStoreCatalogAppDisplay | null;
44
+ }
45
+ /**
46
+ * Projects one catalog app for a consumer: every listed version with its install refusal, the
47
+ * newest install target for this consumer, and the `IAppStoreApp` / `IAppStoreAppMeta` shapes its App Store views
48
+ * show. Pure: it reads the catalog app and never changes it.
49
+ */
50
+ export declare const projectAppStoreCatalogApp: (appArg: TCatalogApp, optionsArg: IAppStoreCatalogProjectionOptions) => IAppStoreCatalogAppProjection;
51
+ /** Projects every catalog app, in catalog order (by id). */
52
+ export declare const projectAppStoreCatalog: (catalogArg: TCatalog, optionsArg: IAppStoreCatalogProjectionOptions) => IAppStoreCatalogAppProjection[];
53
+ /**
54
+ * The App Store listing a consumer serves (`getAppStoreTemplates`): one `IAppStoreApp` per app
55
+ * that has an install target for it, in catalog order. An app without one is left out of the
56
+ * listing; its projection (`projectAppStoreCatalogApp`) still states why.
57
+ */
58
+ export declare const getAppStoreCatalogListing: (catalogArg: TCatalog, optionsArg: IAppStoreCatalogProjectionOptions) => TAppStoreApp[];
59
+ export {};