@camstack/server 1.2.637 → 1.2.638

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.
@@ -1679,6 +1679,7 @@ function buildAddonsProvider(ar, ps, ls, moleculer, configService, ctx, agentReg
1679
1679
  return { success: true };
1680
1680
  },
1681
1681
  getVersions: async (input) => ps.getPackageVersions(input.name),
1682
+ getPackageDocs: async (input) => ps.getPackageDocs(input.name, input.version),
1682
1683
  restartAddon: async (input) => ar.restartAddon(input.addonId),
1683
1684
  retryLoad: async (input) => {
1684
1685
  await ar.retryAddonLoad(input.packageName);
@@ -2,7 +2,7 @@
2
2
  // AUTO-GENERATED by scripts/generate-cap-mounts.ts — DO NOT EDIT
3
3
  // Re-run: npx tsx scripts/generate-cap-mounts.ts
4
4
  //
5
- // Mounted: 179 Skipped (legacy): 3
5
+ // Mounted: 180 Skipped (legacy): 3
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.LEGACY_SHAPE_SKIP = void 0;
8
8
  exports.mountAllCaps = mountAllCaps;
@@ -293,6 +293,7 @@ function mountAllCaps(services) {
293
293
  null, remoteCapProxy),
294
294
  flood: (0, generated_cap_routers_js_1.createCapRouter_flood)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'flood'), remoteCapProxy),
295
295
  gas: (0, generated_cap_routers_js_1.createCapRouter_gas)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'gas'), remoteCapProxy),
296
+ groupCommands: (0, generated_cap_routers_js_1.createCapRouter_groupCommands)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'group-commands'), remoteCapProxy),
296
297
  groupStatus: (0, generated_cap_routers_js_1.createCapRouter_groupStatus)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'group-status'), remoteCapProxy),
297
298
  heatingValve: (0, generated_cap_routers_js_1.createCapRouter_heatingValve)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'heating-valve'), remoteCapProxy),
298
299
  humidifier: (0, generated_cap_routers_js_1.createCapRouter_humidifier)((_ctx) => (0, cap_mount_helpers_js_1.requireDeviceScoped)(reg, 'humidifier'), remoteCapProxy),
@@ -2,7 +2,7 @@
2
2
  // AUTO-GENERATED by scripts/generate-cap-routers.ts — DO NOT EDIT
3
3
  // Re-run: npx tsx scripts/generate-cap-routers.ts
4
4
  //
5
- // Capabilities: 182
5
+ // Capabilities: 183
6
6
  /* eslint-disable */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
8
  exports.requireCapProvider = requireCapProvider;
@@ -80,6 +80,7 @@ exports.createCapRouter_featureProbe = createCapRouter_featureProbe;
80
80
  exports.createCapRouter_filesystemBrowse = createCapRouter_filesystemBrowse;
81
81
  exports.createCapRouter_flood = createCapRouter_flood;
82
82
  exports.createCapRouter_gas = createCapRouter_gas;
83
+ exports.createCapRouter_groupCommands = createCapRouter_groupCommands;
83
84
  exports.createCapRouter_groupStatus = createCapRouter_groupStatus;
84
85
  exports.createCapRouter_heatingValve = createCapRouter_heatingValve;
85
86
  exports.createCapRouter_humidifier = createCapRouter_humidifier;
@@ -704,6 +705,14 @@ function createCapRouter_addons(getProvider, _createRemoteProxy) {
704
705
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
705
706
  return p.getVersions(input);
706
707
  }),
708
+ getPackageDocs: trpc_middleware_js_1.adminProcedure
709
+ .input(types_11.addonsCapability.methods.getPackageDocs.input.loose())
710
+ .output(types_11.addonsCapability.methods.getPackageDocs.output)
711
+ .query(async ({ input, ctx }) => {
712
+ const p = requireCapProvider('addons', () => getProvider(ctx));
713
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
714
+ return p.getPackageDocs(input);
715
+ }),
707
716
  restartAddon: trpc_middleware_js_1.adminProcedure
708
717
  .input(types_11.addonsCapability.methods.restartAddon.input.loose())
709
718
  .output(types_11.addonsCapability.methods.restartAddon.output)
@@ -4785,6 +4794,19 @@ function createCapRouter_gas(getProvider, createRemoteProxy) {
4785
4794
  }),
4786
4795
  });
4787
4796
  }
4797
+ function createCapRouter_groupCommands(getProvider, createRemoteProxy) {
4798
+ return (0, trpc_middleware_js_1.trpcRouter)({
4799
+ getStatus: trpc_middleware_js_1.protectedProcedure
4800
+ .input(types_2.DEVICE_STATUS_METHOD.getStatus.input.loose())
4801
+ .output(types_2.DEVICE_STATUS_METHOD.getStatus.output)
4802
+ .query(async ({ input, ctx }) => {
4803
+ const { nodeId, ...methodInput } = input;
4804
+ const p = resolveProvider('group-commands', nodeId, () => getProvider(ctx), createRemoteProxy);
4805
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
4806
+ return p.getStatus(methodInput);
4807
+ }),
4808
+ });
4809
+ }
4788
4810
  function createCapRouter_groupStatus(getProvider, createRemoteProxy) {
4789
4811
  return (0, trpc_middleware_js_1.trpcRouter)({
4790
4812
  getStatus: trpc_middleware_js_1.protectedProcedure
@@ -49,6 +49,8 @@ const types_2 = require("@camstack/types");
49
49
  const update_availability_emitter_js_1 = require("../update-availability-emitter.js");
50
50
  const update_check_scheduler_js_1 = require("../updates/update-check-scheduler.js");
51
51
  const restart_marker_js_1 = require("../updates/restart-marker.js");
52
+ const package_docs_js_1 = require("./package-docs.js");
53
+ const read_packed_file_js_1 = require("./read-packed-file.js");
52
54
  const package_dir_utils_js_1 = require("./package-dir-utils.js");
53
55
  const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
54
56
  /**
@@ -905,7 +907,7 @@ class AddonPackageService {
905
907
  this.logger.debug('Registry returned non-ok status', {
906
908
  meta: { name, status: response.status },
907
909
  });
908
- return [];
910
+ throw new Error(`registry GET ${name} → ${response.status}`);
909
911
  }
910
912
  const data = await fetchJsonObject(response);
911
913
  const distTags = asRecord(data['dist-tags']);
@@ -948,7 +950,62 @@ class AddonPackageService {
948
950
  catch (error) {
949
951
  const msg = (0, types_2.errMsg)(error);
950
952
  this.logger.warn('Failed to fetch versions', { meta: { name, error: msg } });
951
- return cached?.versions ?? [];
953
+ if (cached)
954
+ return cached.versions;
955
+ throw error;
956
+ }
957
+ }
958
+ /**
959
+ * README (packument) and CHANGELOG (tarball) for one published package.
960
+ * Cached inside the reader. Registry failures stay typed on the document
961
+ * that failed — this method does not throw them away as an empty string.
962
+ */
963
+ async getPackageDocs(name, version) {
964
+ return this.docsReader().load(name, version);
965
+ }
966
+ packageDocsReader = null;
967
+ docsReader() {
968
+ if (this.packageDocsReader)
969
+ return this.packageDocsReader;
970
+ const reader = (0, package_docs_js_1.createPackageDocsReader)({
971
+ client: {
972
+ fetchPackument: (packageName) => this.fetchPackumentDocument(packageName),
973
+ fetchTarball: (url) => this.fetchTarballDocument(url),
974
+ readChangelog: (bytes) => (0, read_packed_file_js_1.readPackedChangelog)(bytes),
975
+ },
976
+ });
977
+ this.packageDocsReader = reader;
978
+ return reader;
979
+ }
980
+ async fetchPackumentDocument(name) {
981
+ const encodedName = name.replace('/', '%2F');
982
+ const url = `${this.resolveRegistryBase()}/${encodedName}`;
983
+ try {
984
+ const response = await fetch(url, {
985
+ signal: AbortSignal.timeout(AddonPackageService.REGISTRY_TIMEOUT_MS),
986
+ });
987
+ if (!response.ok) {
988
+ return { ok: false, message: `registry GET ${name} → ${response.status}` };
989
+ }
990
+ const body = await response.json();
991
+ return { ok: true, body };
992
+ }
993
+ catch (error) {
994
+ return { ok: false, message: (0, types_2.errMsg)(error) };
995
+ }
996
+ }
997
+ async fetchTarballDocument(url) {
998
+ try {
999
+ const response = await fetch(url, {
1000
+ signal: AbortSignal.timeout(AddonPackageService.REGISTRY_TIMEOUT_MS),
1001
+ });
1002
+ if (!response.ok) {
1003
+ return { ok: false, message: `tarball GET ${url} → ${response.status}` };
1004
+ }
1005
+ return { ok: true, bytes: Buffer.from(await response.arrayBuffer()) };
1006
+ }
1007
+ catch (error) {
1008
+ return { ok: false, message: (0, types_2.errMsg)(error) };
952
1009
  }
953
1010
  }
954
1011
  // =========================================================================
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ /**
3
+ * README and CHANGELOG for one published package, read on the hub.
4
+ *
5
+ * README is the npm packument `readme` (the version's own field, else the
6
+ * packument root). CHANGELOG is `CHANGELOG.md` inside that version's tarball.
7
+ * A registry failure is a typed `error` on the side that failed — never an
8
+ * empty document. `missing` means the registry answered and the file was not
9
+ * there. Successful and missing answers are cached; errors are not, so the
10
+ * next open retries.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.PACKAGE_DOCS_TTL_MS = void 0;
14
+ exports.createPackageDocsReader = createPackageDocsReader;
15
+ exports.PACKAGE_DOCS_TTL_MS = 10 * 60 * 1000;
16
+ function asRecord(value) {
17
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
18
+ return { ...value };
19
+ }
20
+ return {};
21
+ }
22
+ function asString(value) {
23
+ return typeof value === 'string' ? value : '';
24
+ }
25
+ function docFromMarkdown(markdown) {
26
+ const trimmed = markdown.trim();
27
+ if (trimmed.length === 0)
28
+ return { status: 'missing' };
29
+ return { status: 'ok', markdown };
30
+ }
31
+ function errorDocs(name, version, message) {
32
+ const body = { status: 'error', message };
33
+ return { name, version, readme: body, changelog: body };
34
+ }
35
+ function resolvePackument(body, requested) {
36
+ const packument = asRecord(body);
37
+ const distTags = asRecord(packument['dist-tags']);
38
+ const versions = asRecord(packument['versions']);
39
+ const tagged = requested === undefined ? asString(distTags['latest']) : '';
40
+ const named = requested !== undefined && versions[requested] !== undefined ? requested : '';
41
+ const fromTag = requested !== undefined ? asString(distTags[requested]) : '';
42
+ const version = named || fromTag || tagged;
43
+ if (version.length === 0 || versions[version] === undefined) {
44
+ return {
45
+ status: 'error',
46
+ message: requested === undefined
47
+ ? 'packument has no latest version'
48
+ : `no version resolved for ${requested}`,
49
+ };
50
+ }
51
+ const meta = asRecord(versions[version]);
52
+ const dist = asRecord(meta['dist']);
53
+ const versionReadme = asString(meta['readme']);
54
+ const rootReadme = asString(packument['readme']);
55
+ const tarball = asString(dist['tarball']);
56
+ return {
57
+ status: 'ok',
58
+ version,
59
+ readme: versionReadme.length > 0 ? versionReadme : rootReadme,
60
+ tarballUrl: tarball.length > 0 ? tarball : null,
61
+ };
62
+ }
63
+ function cacheable(docs) {
64
+ return docs.readme.status !== 'error' && docs.changelog.status !== 'error';
65
+ }
66
+ function createPackageDocsReader(options) {
67
+ const cache = new Map();
68
+ const now = options.now ?? (() => Date.now());
69
+ const ttlMs = options.ttlMs ?? exports.PACKAGE_DOCS_TTL_MS;
70
+ async function load(name, requested) {
71
+ const directKey = requested !== undefined ? `${name}@${requested}` : `${name}@`;
72
+ const hit = cache.get(directKey);
73
+ if (hit !== undefined && hit.expiresAt > now())
74
+ return hit.docs;
75
+ const packument = await options.client.fetchPackument(name);
76
+ if (!packument.ok)
77
+ return errorDocs(name, requested ?? '', packument.message);
78
+ const resolved = resolvePackument(packument.body, requested);
79
+ if (resolved.status === 'error')
80
+ return errorDocs(name, requested ?? '', resolved.message);
81
+ const key = `${name}@${resolved.version}`;
82
+ const resolvedHit = cache.get(key);
83
+ if (resolvedHit !== undefined && resolvedHit.expiresAt > now())
84
+ return resolvedHit.docs;
85
+ const readme = docFromMarkdown(resolved.readme);
86
+ const changelog = await loadChangelog(name, resolved.version, resolved.tarballUrl, options.client);
87
+ const docs = { name, version: resolved.version, readme, changelog };
88
+ if (cacheable(docs)) {
89
+ const entry = { docs, expiresAt: now() + ttlMs };
90
+ cache.set(key, entry);
91
+ cache.set(directKey, entry);
92
+ }
93
+ return docs;
94
+ }
95
+ return { load };
96
+ }
97
+ async function loadChangelog(name, version, tarballUrl, client) {
98
+ if (tarballUrl === null) {
99
+ return { status: 'error', message: `no tarball url for ${name}@${version}` };
100
+ }
101
+ const tarball = await client.fetchTarball(tarballUrl);
102
+ if (!tarball.ok)
103
+ return { status: 'error', message: tarball.message };
104
+ try {
105
+ const text = await client.readChangelog(tarball.bytes);
106
+ if (text === null)
107
+ return { status: 'missing' };
108
+ return docFromMarkdown(text);
109
+ }
110
+ catch (err) {
111
+ const message = err instanceof Error ? err.message : 'changelog read failed';
112
+ return { status: 'error', message };
113
+ }
114
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.isPackedChangelogPath = isPackedChangelogPath;
37
+ exports.readPackedChangelog = readPackedChangelog;
38
+ /**
39
+ * Read one file out of an npm tarball without unpacking the rest.
40
+ *
41
+ * npm packs the package under a `package/` prefix. A changelog the registry
42
+ * page shows is `package/CHANGELOG.md` (or the same name at the archive root).
43
+ * Nested copies (`package/docs/CHANGELOG.md`) are not the package changelog.
44
+ */
45
+ const node_child_process_1 = require("node:child_process");
46
+ const fs = __importStar(require("node:fs"));
47
+ const os = __importStar(require("node:os"));
48
+ const path = __importStar(require("node:path"));
49
+ const node_util_1 = require("node:util");
50
+ const node_crypto_1 = require("node:crypto");
51
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
52
+ const TAR_TIMEOUT_MS = 30_000;
53
+ const TAR_MAX_BUFFER = 2_000_000;
54
+ /** True for `CHANGELOG.md` or `package/CHANGELOG.md`, any letter case. */
55
+ function isPackedChangelogPath(entry) {
56
+ const parts = entry.split('/').filter((part) => part.length > 0);
57
+ if (parts.length !== 1 && parts.length !== 2)
58
+ return false;
59
+ const base = parts[parts.length - 1] ?? '';
60
+ return base.toLowerCase() === 'changelog.md';
61
+ }
62
+ /**
63
+ * Returns the changelog text, or `null` when the archive has no
64
+ * `CHANGELOG.md`. Throws when `tar` itself fails.
65
+ */
66
+ async function readPackedChangelog(tgz) {
67
+ const tmpFile = path.join(os.tmpdir(), `camstack-docs-${(0, node_crypto_1.randomUUID)()}.tgz`);
68
+ fs.writeFileSync(tmpFile, tgz);
69
+ try {
70
+ const listed = await execFileAsync('tar', ['-tzf', tmpFile], {
71
+ timeout: TAR_TIMEOUT_MS,
72
+ maxBuffer: TAR_MAX_BUFFER,
73
+ encoding: 'utf8',
74
+ });
75
+ const entry = listed.stdout
76
+ .split('\n')
77
+ .map((line) => line.trim())
78
+ .find((line) => isPackedChangelogPath(line));
79
+ if (entry === undefined)
80
+ return null;
81
+ const extracted = await execFileAsync('tar', ['-xOzf', tmpFile, entry], {
82
+ timeout: TAR_TIMEOUT_MS,
83
+ maxBuffer: TAR_MAX_BUFFER,
84
+ encoding: 'utf8',
85
+ });
86
+ return extracted.stdout;
87
+ }
88
+ finally {
89
+ fs.rmSync(tmpFile, { force: true });
90
+ }
91
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.637",
3
+ "version": "1.2.638",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -47,20 +47,20 @@
47
47
  ]
48
48
  },
49
49
  "dependencies": {
50
- "@camstack/addon-admin-ui": "1.2.474",
51
- "@camstack/addon-agent-ui": "1.2.272",
52
- "@camstack/addon-auth": "1.2.168",
53
- "@camstack/addon-benchmark": "1.2.271",
54
- "@camstack/addon-decoder-nodeav": "1.2.142",
55
- "@camstack/addon-notifiers": "1.2.621",
56
- "@camstack/addon-pipeline": "1.2.628",
57
- "@camstack/addon-pipeline-orchestrator": "1.2.630",
58
- "@camstack/addon-post-analysis": "1.2.637",
50
+ "@camstack/addon-admin-ui": "1.2.475",
51
+ "@camstack/addon-agent-ui": "1.2.273",
52
+ "@camstack/addon-auth": "1.2.169",
53
+ "@camstack/addon-benchmark": "1.2.272",
54
+ "@camstack/addon-decoder-nodeav": "1.2.143",
55
+ "@camstack/addon-notifiers": "1.2.622",
56
+ "@camstack/addon-pipeline": "1.2.629",
57
+ "@camstack/addon-pipeline-orchestrator": "1.2.631",
58
+ "@camstack/addon-post-analysis": "1.2.638",
59
59
  "@camstack/develop": "0.1.36",
60
60
  "@camstack/sdk": "1.2.153",
61
- "@camstack/system": "1.2.486",
62
- "@camstack/types": "1.2.418",
63
- "@camstack/ui-library": "1.2.328",
61
+ "@camstack/system": "1.2.487",
62
+ "@camstack/types": "1.2.419",
63
+ "@camstack/ui-library": "1.2.329",
64
64
  "@fastify/compress": "^9.0.0",
65
65
  "@fastify/cookie": "^11.0.2",
66
66
  "@fastify/cors": "^11.2.0",