@uns-kit/core 3.0.47 → 3.0.49
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/MIGRATIONS.md +27 -0
- package/README.md +24 -22
- package/dist/runtime/service-access-examples/README.md +21 -0
- package/dist/runtime/service-access-examples/background-reader/README.md +29 -0
- package/dist/runtime/service-access-examples/background-reader/build.mjs +7 -0
- package/dist/runtime/service-access-examples/background-reader/config-example.json +22 -0
- package/dist/runtime/service-access-examples/background-reader/package.json +37 -0
- package/dist/runtime/service-access-examples/background-reader/src/index.mjs +55 -0
- package/dist/runtime/service-access-examples/background-reader/src/reader.mjs +26 -0
- package/dist/runtime/service-access-examples/catalog-summary/README.md +30 -0
- package/dist/runtime/service-access-examples/catalog-summary/build.mjs +7 -0
- package/dist/runtime/service-access-examples/catalog-summary/config-example.json +23 -0
- package/dist/runtime/service-access-examples/catalog-summary/package.json +92 -0
- package/dist/runtime/service-access-examples/catalog-summary/src/index.mjs +50 -0
- package/dist/runtime/service-access-examples/catalog-summary/src/offer.mjs +35 -0
- package/dist/runtime/service-access-guide.md +259 -112
- package/dist/runtime/service-access-package.d.ts +6 -0
- package/dist/runtime/service-access-package.d.ts.map +1 -0
- package/dist/runtime/service-access-package.js +45 -0
- package/dist/runtime/service-access-package.js.map +1 -0
- package/dist/runtime/service-access-package.test.d.ts +2 -0
- package/dist/runtime/service-access-package.test.d.ts.map +1 -0
- package/dist/runtime/service-access-package.test.js +61 -0
- package/dist/runtime/service-access-package.test.js.map +1 -0
- package/dist/runtime/service-access.d.ts +26 -0
- package/dist/runtime/service-access.d.ts.map +1 -1
- package/dist/runtime/service-access.js +23 -0
- package/dist/runtime/service-access.js.map +1 -1
- package/package.json +1 -1
|
@@ -36,6 +36,29 @@ export function parseServiceAccessDeclaration(value) {
|
|
|
36
36
|
throw Error("service_access_capability_required");
|
|
37
37
|
return { protocol: 1, permissions, ...(publications ? { publications } : {}) };
|
|
38
38
|
}
|
|
39
|
+
/** Package metadata accepts one inline declaration or one safe relative JSON
|
|
40
|
+
* reference. Both normalize through the same parser; neither grants authority. */
|
|
41
|
+
export const serviceAccessPackageReferenceSchema = z.union([
|
|
42
|
+
z.string().min(1).max(512).refine((value) => !value.includes("\\") && !value.startsWith("/") &&
|
|
43
|
+
!/^[A-Za-z]:/.test(value) &&
|
|
44
|
+
value.split("/").every((part) => !!part && part !== "." && part !== ".."), "Expected a package-relative declaration path"),
|
|
45
|
+
envelope.transform(parseServiceAccessDeclaration),
|
|
46
|
+
]);
|
|
47
|
+
export async function resolveServiceAccessDeclaration(packageJson, readDeclaration) {
|
|
48
|
+
const pkg = z.object({
|
|
49
|
+
unsDatahub: z.object({
|
|
50
|
+
serviceAccess: z.unknown().optional(),
|
|
51
|
+
catalogAccess: z.unknown().optional(),
|
|
52
|
+
}).passthrough().optional(),
|
|
53
|
+
}).passthrough().parse(packageJson);
|
|
54
|
+
const metadata = pkg.unsDatahub;
|
|
55
|
+
if (metadata?.serviceAccess === undefined)
|
|
56
|
+
return null;
|
|
57
|
+
if (metadata.catalogAccess !== undefined)
|
|
58
|
+
throw Error("service_access_declaration_conflict");
|
|
59
|
+
const reference = serviceAccessPackageReferenceSchema.parse(metadata.serviceAccess);
|
|
60
|
+
return parseServiceAccessDeclaration(typeof reference === "string" ? await readDeclaration(reference) : reference);
|
|
61
|
+
}
|
|
39
62
|
export const serviceAccessDigest = operatorDigest;
|
|
40
63
|
/** Publication source rules are deliberately not raw UNS permissions. A service
|
|
41
64
|
* combining a background reader with a catalog must not gain their cross-product. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-access.js","sourceRoot":"","sources":["../../src/runtime/service-access.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { CATALOG_SOURCE_SCOPE, type CatalogPublicationManifest, parseCatalogPublicationManifest } from \"./catalog-publication.js\";\nimport { operatorDigest, operatorJson } from \"./operator-api.js\";\n\nexport const SERVICE_ACCESS_PROTOCOL = 1;\nexport const SERVICE_ACCESS_MANIFEST_FIELD = \"serviceAccess\";\n// Only existing platform data/runtime capabilities. Administrative authority is\n// never a package-requestable scope. UNS rules bound direct UNS reads; other\n// runtime capabilities retain their existing platform authorization semantics.\nexport const SERVICE_RESOURCE_SCOPES = [\n \"read:uns\",\n \"identity:asset:publish\",\n \"runtime:captures:read\",\n \"runtime:captures:write\",\n \"runtime:triggers:read\",\n] as const;\nconst rule = z\n .string()\n .min(1)\n .max(512)\n .refine((s) => s.split(\"/\").every((p, i, a) => p === \"+\" || (p === \"#\" && i === a.length - 1) || /^[A-Za-z0-9-]+$/.test(p)));\nconst envelope = z\n .object({\n protocol: z.literal(1),\n permissions: z.object({ scopes: z.array(z.enum(SERVICE_RESOURCE_SCOPES)).max(5), accessRules: z.array(rule).max(64) }).strict(),\n publications: z.unknown().optional(),\n })\n .strict();\nexport type ServiceAccessDeclaration = {\n protocol: 1;\n permissions: { scopes: string[]; accessRules: string[] };\n publications?: CatalogPublicationManifest;\n};\nexport function parseServiceAccessDeclaration(value: unknown): ServiceAccessDeclaration {\n operatorJson(value);\n const parsed = envelope.parse(value);\n const permissions = { scopes: [...new Set(parsed.permissions.scopes)].sort(), accessRules: [...new Set(parsed.permissions.accessRules)].sort() };\n if (!!permissions.scopes.length !== !!permissions.accessRules.length) throw Error(\"service_access_resources_required\");\n const publications = parsed.publications === undefined ? undefined : parseCatalogPublicationManifest(parsed.publications);\n if (!permissions.scopes.length && !publications) throw Error(\"service_access_capability_required\");\n return { protocol: 1, permissions, ...(publications ? { publications } : {}) };\n}\nexport const serviceAccessDigest = operatorDigest;\n/** Publication source rules are deliberately not raw UNS permissions. A service\n * combining a background reader with a catalog must not gain their cross-product. */\nexport function serviceAccessCeiling(declaration: ServiceAccessDeclaration) {\n return {\n scopes: [...declaration.permissions.scopes, ...(declaration.publications ? [CATALOG_SOURCE_SCOPE] : [])].sort(),\n accessRules: [...declaration.permissions.accessRules],\n };\n}\n/** Conservative MQTT filter inclusion, not matching a filter as if it were data. */\nexport function serviceRuleWithin(requested: string, allowed: string): boolean {\n const a = allowed.split(\"/\"),\n r = requested.split(\"/\");\n let i = 0;\n for (; i < a.length; i++) {\n if (a[i] === \"#\") return true;\n if (r[i] === undefined || r[i] === \"#\") return false;\n if (a[i] !== r[i] && a[i] !== \"+\") return false;\n }\n return i === r.length;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"service-access.js","sourceRoot":"","sources":["../../src/runtime/service-access.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nimport { CATALOG_SOURCE_SCOPE, type CatalogPublicationManifest, parseCatalogPublicationManifest } from \"./catalog-publication.js\";\nimport { operatorDigest, operatorJson } from \"./operator-api.js\";\n\nexport const SERVICE_ACCESS_PROTOCOL = 1;\nexport const SERVICE_ACCESS_MANIFEST_FIELD = \"serviceAccess\";\n// Only existing platform data/runtime capabilities. Administrative authority is\n// never a package-requestable scope. UNS rules bound direct UNS reads; other\n// runtime capabilities retain their existing platform authorization semantics.\nexport const SERVICE_RESOURCE_SCOPES = [\n \"read:uns\",\n \"identity:asset:publish\",\n \"runtime:captures:read\",\n \"runtime:captures:write\",\n \"runtime:triggers:read\",\n] as const;\nconst rule = z\n .string()\n .min(1)\n .max(512)\n .refine((s) => s.split(\"/\").every((p, i, a) => p === \"+\" || (p === \"#\" && i === a.length - 1) || /^[A-Za-z0-9-]+$/.test(p)));\nconst envelope = z\n .object({\n protocol: z.literal(1),\n permissions: z.object({ scopes: z.array(z.enum(SERVICE_RESOURCE_SCOPES)).max(5), accessRules: z.array(rule).max(64) }).strict(),\n publications: z.unknown().optional(),\n })\n .strict();\nexport type ServiceAccessDeclaration = {\n protocol: 1;\n permissions: { scopes: string[]; accessRules: string[] };\n publications?: CatalogPublicationManifest;\n};\nexport function parseServiceAccessDeclaration(value: unknown): ServiceAccessDeclaration {\n operatorJson(value);\n const parsed = envelope.parse(value);\n const permissions = { scopes: [...new Set(parsed.permissions.scopes)].sort(), accessRules: [...new Set(parsed.permissions.accessRules)].sort() };\n if (!!permissions.scopes.length !== !!permissions.accessRules.length) throw Error(\"service_access_resources_required\");\n const publications = parsed.publications === undefined ? undefined : parseCatalogPublicationManifest(parsed.publications);\n if (!permissions.scopes.length && !publications) throw Error(\"service_access_capability_required\");\n return { protocol: 1, permissions, ...(publications ? { publications } : {}) };\n}\n\n/** Package metadata accepts one inline declaration or one safe relative JSON\n * reference. Both normalize through the same parser; neither grants authority. */\nexport const serviceAccessPackageReferenceSchema = z.union([\n z.string().min(1).max(512).refine(\n (value) => !value.includes(\"\\\\\") && !value.startsWith(\"/\") &&\n !/^[A-Za-z]:/.test(value) &&\n value.split(\"/\").every((part) => !!part && part !== \".\" && part !== \"..\"),\n \"Expected a package-relative declaration path\",\n ),\n envelope.transform(parseServiceAccessDeclaration),\n]);\n\nexport type ServiceAccessPackageReference = string | ServiceAccessDeclaration;\n\nexport async function resolveServiceAccessDeclaration(\n packageJson: unknown,\n readDeclaration: (relativePath: string) => Promise<unknown>,\n): Promise<ServiceAccessDeclaration | null> {\n const pkg = z.object({\n unsDatahub: z.object({\n serviceAccess: z.unknown().optional(),\n catalogAccess: z.unknown().optional(),\n }).passthrough().optional(),\n }).passthrough().parse(packageJson);\n const metadata = pkg.unsDatahub;\n if (metadata?.serviceAccess === undefined) return null;\n if (metadata.catalogAccess !== undefined) throw Error(\"service_access_declaration_conflict\");\n const reference = serviceAccessPackageReferenceSchema.parse(metadata.serviceAccess);\n return parseServiceAccessDeclaration(\n typeof reference === \"string\" ? await readDeclaration(reference) : reference,\n );\n}\nexport const serviceAccessDigest = operatorDigest;\n/** Publication source rules are deliberately not raw UNS permissions. A service\n * combining a background reader with a catalog must not gain their cross-product. */\nexport function serviceAccessCeiling(declaration: ServiceAccessDeclaration) {\n return {\n scopes: [...declaration.permissions.scopes, ...(declaration.publications ? [CATALOG_SOURCE_SCOPE] : [])].sort(),\n accessRules: [...declaration.permissions.accessRules],\n };\n}\n/** Conservative MQTT filter inclusion, not matching a filter as if it were data. */\nexport function serviceRuleWithin(requested: string, allowed: string): boolean {\n const a = allowed.split(\"/\"),\n r = requested.split(\"/\");\n let i = 0;\n for (; i < a.length; i++) {\n if (a[i] === \"#\") return true;\n if (r[i] === undefined || r[i] === \"#\") return false;\n if (a[i] !== r[i] && a[i] !== \"+\") return false;\n }\n return i === r.length;\n}\n"]}
|