@sema-agent/primitives 0.0.0-stage → 7.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,106 @@
1
+ Business Source License 1.1
2
+
3
+ Parameters
4
+
5
+ Licensor: clay (github.com/clayboby)
6
+ Licensed Work: @sema-agent/core (sema-core) and the satellite packages
7
+ published from this repository (currently
8
+ @sema-agent/mods-kernel, @sema-agent/primitives and @sema-agent/core-stores-sql)
9
+ (formerly published as @sema-ai/core)
10
+ The Licensed Work is (c) 2026 clay.
11
+ Additional Use Grant: You may make production use of the Licensed Work for
12
+ personal, educational, research, or other
13
+ non-commercial purposes. Commercial production use
14
+ requires a commercial license from the Licensor.
15
+ Change Date: 2030-07-13
16
+ Change License: Apache License, Version 2.0
17
+
18
+ For information about alternative licensing arrangements for the Licensed
19
+ Work, please contact the Licensor.
20
+
21
+ Notice
22
+
23
+ The Business Source License (this document, or the "License") is not an Open
24
+ Source license. However, the Licensed Work will eventually be made available
25
+ under an Open Source License, as stated in this License.
26
+
27
+ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
28
+ "Business Source License" is a trademark of MariaDB Corporation Ab.
29
+
30
+ -----------------------------------------------------------------------------
31
+
32
+ Terms
33
+
34
+ The Licensor hereby grants you the right to copy, modify, create derivative
35
+ works, redistribute, and make non-production use of the Licensed Work. The
36
+ Licensor may make an Additional Use Grant, above, permitting limited
37
+ production use.
38
+
39
+ Effective on the Change Date, or the fourth anniversary of the first publicly
40
+ available distribution of a specific version of the Licensed Work under this
41
+ License, whichever comes first, the Licensor hereby grants you rights under
42
+ the terms of the Change License, and the rights granted in the paragraph
43
+ above terminate.
44
+
45
+ If your use of the Licensed Work does not comply with the requirements
46
+ currently in effect as described in this License, you must purchase a
47
+ commercial license from the Licensor, its affiliated entities, or authorized
48
+ resellers, or you must refrain from using the Licensed Work.
49
+
50
+ All copies of the original and modified Licensed Work, and derivative works
51
+ of the Licensed Work, are subject to this License. This License applies
52
+ separately for each version of the Licensed Work and the Change Date may vary
53
+ for each version of the Licensed Work released by Licensor.
54
+
55
+ You must conspicuously display this License on each original or modified copy
56
+ of the Licensed Work. If you receive the Licensed Work in original or
57
+ modified form from a third party, the terms and conditions set forth in this
58
+ License apply to your use of that work.
59
+
60
+ Any use of the Licensed Work in violation of this License will automatically
61
+ terminate your rights under this License for the current and all other
62
+ versions of the Licensed Work.
63
+
64
+ This License does not grant you any right in any trademark or logo of
65
+ Licensor or its affiliates (provided that you may use a trademark or logo of
66
+ Licensor as expressly required by this License).
67
+
68
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
69
+ AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
70
+ EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
71
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
72
+ TITLE.
73
+
74
+ MariaDB hereby grants you permission to use this License's text to license
75
+ your works, and to refer to it using the trademark "Business Source License",
76
+ as long as you comply with the Covenants of Licensor below.
77
+
78
+ Covenants of Licensor
79
+
80
+ In consideration of the right to use this License's text and the "Business
81
+ Source License" name and trademark, Licensor covenants to MariaDB, and to all
82
+ other recipients of the licensed work to be provided by Licensor:
83
+
84
+ 1. To specify as the Change License the GPL Version 2.0 or any later version,
85
+ or a license that is compatible with GPL Version 2.0 or a later version,
86
+ where "compatible" means that software provided under the Change License can
87
+ be included in a program with software provided under GPL Version 2.0 or a
88
+ later version. Licensor may specify additional Change Licenses without
89
+ limitation.
90
+
91
+ 2. To either: (a) specify an additional grant of rights to use that does not
92
+ impose any additional restriction on the right granted in this License, as
93
+ the Additional Use Grant; or (b) insert the text "None".
94
+
95
+ 3. To specify a Change Date.
96
+
97
+ 4. Not to modify this License in any other way.
98
+
99
+ -----------------------------------------------------------------------------
100
+
101
+ Third-party notices
102
+
103
+ Versions of this package up to and including 1.277.1 were published under the
104
+ MIT License; those published copies remain governed by the license they were
105
+ distributed under. This package incorporates design and (where noted) prompt
106
+ content adapted from MIT-licensed projects — see NOTICE.md for attributions.
package/README.md CHANGED
@@ -1,3 +1,94 @@
1
- # Temporary Holding Version
1
+ # @sema-agent/primitives
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Low-level definitions of the sema engine that every layer may import: no policy of any layer, no state, no
4
+ dependencies. Today it holds one member, the credential reference. It is compiled from the same source the engine
5
+ embeds, so an acceptance gate, a settings validator or an admin form reads the same closed set through the same function
6
+ as the engine does. Runs in Node and in browsers; ships its own types.
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ npm install @sema-agent/primitives
12
+ ```
13
+
14
+ ES modules only (`"type": "module"`), Node >= 20.18.1 where Node is used. One entry, `.`; there are no deep paths.
15
+
16
+ ## Version
17
+
18
+ `@sema-agent/primitives@X.Y.Z` is cut with `@sema-agent/core@X.Y.Z`: the same version number, built from the same
19
+ commit. A package version moves with every core release whether or not the primitives changed.
20
+
21
+ ## The credential reference
22
+
23
+ A declaration names a credential by reference instead of carrying its value. The reference is one of a closed set of
24
+ kinds; whoever resolves it (a deployment's seat, not this package) decides what the name means and whether this
25
+ declaration may use it.
26
+
27
+ | `kind` | Members | Request surface (`CREDENTIAL_REF_TRUST[kind].request`) |
28
+ | --- | --- | --- |
29
+ | `env` | `headers?`: header name → variable name · `env?`: child variable → variable name (at least one) | `refused` |
30
+ | `vault` | `entry`: a stored credential entry | `own_entry` — only an entry that belongs to the submitting principal |
31
+ | `handle` | `id`: an opaque id the deployment minted | `refused` |
32
+ | `assertion` | `audience`: what a short-lived assertion is requested for | `refused` |
33
+
34
+ `readCredentialRef(value)` answers `{ ok: true, ref }` with a fresh frozen copy (forward the copy, never the value you
35
+ read), or `{ ok: false, problem }`. Each fault is its own `reason`, and the first one found is the one reported, in this
36
+ order: not a record; `kind` absent, not text or unknown; an extra member; a missing member; a bad value. The reader does not throw: a value whose members cannot be read (a revoked or throwing Proxy) is
37
+ `not_a_record` (or, inside a name map, that map's `bad_value`). With no stack left a valid value may be refused, under any
38
+ reason, and never an invalid one accepted; the call itself may throw a `RangeError` before it is entered, which no function
39
+ can catch.
40
+
41
+ | `reason` | Meaning |
42
+ | --- | --- |
43
+ | `not_a_record` | not an ordinary record (a primitive, `null`, an array, a class instance, a `Map`, a `Date`), or one whose members cannot be read; an object whose prototype is none or itself has none — the `Object.prototype` of any realm is one — is a record |
44
+ | `unknown_kind` | `kind` is text outside `CREDENTIAL_REF_KINDS` (every spelling the set does not hold: another case, padded, zero-width, full-width, a look-alike letter) |
45
+ | `extra_field` | a member the kind does not have (a member spelled in another case is one) |
46
+ | `missing_field` | `kind`, or a member the kind needs, is absent (for `env`: neither `headers` nor `env`, field `headers\|env`) |
47
+ | `bad_value` | a member of the wrong form (below) |
48
+
49
+ A member is an own enumerable string-keyed data property. A getter is refused and never called, nothing is read through a
50
+ prototype, a key present with the value `undefined` is a bad value (not an absent member), and a non-enumerable or
51
+ symbol-keyed member is not read and not copied.
52
+
53
+ `bad_value` is: for `kind`, anything but text; for a text member (`entry`, `id`, `audience`), anything but 1 to
54
+ `CREDENTIAL_REF_TEXT_MAX` (2048) UTF-16 code units with no control, format or line-separator character (C0 and C1,
55
+ zero-width, bidi override, soft hyphen, BOM, U+2028 / U+2029), no default-ignorable, noncharacter or private-use character, no lone surrogate and no leading or trailing white space;
56
+ for a name map (`headers`, `env`), anything but a record of 1 to `CREDENTIAL_REF_MAP_MAX` (64) entries whose names are
57
+ within the grammar (a header name is an HTTP token; a child variable name and every variable name is
58
+ `[A-Za-z_][A-Za-z0-9_]*`) and within the text bound, and — for `headers`, whose names are case-insensitive — in which no
59
+ two names differ only by case. The maps come back frozen and without a prototype: an absent name reads `undefined`, and an
60
+ own `__proto__` name is a plain key. Text is compared as written; nothing is normalised (two spellings of one visible
61
+ string are two entries; visually confusable text — homoglyphs, a braille blank, stacked combining marks — is not judged, and
62
+ an emoji presentation selector or a zero-width joiner is refused, because these members are identifiers, not prose). The text
63
+ bound counts UTF-16 code units (up to 6144 UTF-8 bytes), and the character classes are the
64
+ host's Unicode tables, so two surfaces on engines with different Unicode versions can differ for a recently added character.
65
+
66
+ ```js
67
+ import { readCredentialRef } from "@sema-agent/primitives";
68
+
69
+ readCredentialRef({ kind: "vault", entry: "github-main" }); // { ok: true, ref: { kind: "vault", entry: "github-main" } }
70
+ readCredentialRef({ kind: "vault2", entry: "x" }); // { ok: false, problem: { reason: "unknown_kind", kind: "vault2" } }
71
+ readCredentialRef({ kind: "handle" }); // { ok: false, problem: { reason: "missing_field", kind: "handle", field: "id" } }
72
+ readCredentialRef({ kind: "handle", id: "h1", note: "x" }); // { ok: false, problem: { reason: "extra_field", kind: "handle", field: "note" } }
73
+ ```
74
+
75
+ A `kind` or `field` the reader echoes back is the caller's text, cut to 64 characters with control, format and
76
+ line-separator characters and lone surrogates replaced; fence it before rendering it where markup is interpreted. A Proxy's
77
+ own traps (on the value, its maps or its prototype) are the caller's code and run as they would for any property read.
78
+
79
+ The reader judges shape only: it does not know whether a variable exists, whether an entry belongs to anyone, which header
80
+ names a deployment forbids (the protocol's own names, a principal header), which child variables a declaration may set, or
81
+ whether a reference may reach a destination. Those are the policy of the layer that reads the reference.
82
+
83
+ `CREDENTIAL_REF_TRUST` has a row for each kind and for nothing else (it has no prototype, so no inherited member answers);
84
+ look a kind up in it only after `readCredentialRef` has accepted the value.
85
+
86
+ ## Exports
87
+
88
+ Each name below is a runtime value or a type exported from the package root. The root's declarations are the contract; a
89
+ removed or re-kinded export is named as breaking in the `@sema-agent/core` release notes.
90
+
91
+ | Group | Names |
92
+ | --- | --- |
93
+ | Credential reference | `readCredentialRef` `CREDENTIAL_REF_KINDS` `CREDENTIAL_REF_TRUST` `CREDENTIAL_REF_TEXT_MAX` `CREDENTIAL_REF_MAP_MAX` `CREDENTIAL_REF_PROBLEM_REASONS` |
94
+ | Types | `CredentialRef` `CredentialRefKind` `CredentialRefRequestAdmission` `CredentialRefProblem` `CredentialRefProblemReason` `CredentialRefReading` |
@@ -0,0 +1,52 @@
1
+ export declare const CREDENTIAL_REF_KINDS: readonly ["env", "vault", "handle", "assertion"];
2
+ export type CredentialRefKind = (typeof CREDENTIAL_REF_KINDS)[number];
3
+ export type CredentialRef = {
4
+ readonly kind: "env";
5
+ readonly headers?: Readonly<Record<string, string>>;
6
+ readonly env?: Readonly<Record<string, string>>;
7
+ } | {
8
+ readonly kind: "vault";
9
+ readonly entry: string;
10
+ } | {
11
+ readonly kind: "handle";
12
+ readonly id: string;
13
+ } | {
14
+ readonly kind: "assertion";
15
+ readonly audience: string;
16
+ };
17
+ export type CredentialRefRequestAdmission = "refused" | "own_entry";
18
+ type TrustRow = {
19
+ readonly request: CredentialRefRequestAdmission;
20
+ };
21
+ export declare const CREDENTIAL_REF_TRUST: Readonly<Record<CredentialRefKind, TrustRow>>;
22
+ export declare const CREDENTIAL_REF_TEXT_MAX = 2048;
23
+ export declare const CREDENTIAL_REF_MAP_MAX = 64;
24
+ export declare const CREDENTIAL_REF_PROBLEM_REASONS: readonly ["not_a_record", "unknown_kind", "missing_field", "extra_field", "bad_value"];
25
+ export type CredentialRefProblemReason = (typeof CREDENTIAL_REF_PROBLEM_REASONS)[number];
26
+ export type CredentialRefProblem = {
27
+ readonly reason: "not_a_record";
28
+ } | {
29
+ readonly reason: "unknown_kind";
30
+ readonly kind: string;
31
+ } | {
32
+ readonly reason: "missing_field";
33
+ readonly kind?: CredentialRefKind;
34
+ readonly field: string;
35
+ } | {
36
+ readonly reason: "extra_field";
37
+ readonly kind: CredentialRefKind;
38
+ readonly field: string;
39
+ } | {
40
+ readonly reason: "bad_value";
41
+ readonly kind?: CredentialRefKind;
42
+ readonly field: string;
43
+ };
44
+ export type CredentialRefReading = {
45
+ readonly ok: true;
46
+ readonly ref: CredentialRef;
47
+ } | {
48
+ readonly ok: false;
49
+ readonly problem: CredentialRefProblem;
50
+ };
51
+ export declare function readCredentialRef(value: unknown): CredentialRefReading;
52
+ export {};
@@ -0,0 +1,125 @@
1
+ export const CREDENTIAL_REF_KINDS = Object.freeze(["env", "vault", "handle", "assertion"]);
2
+ export const CREDENTIAL_REF_TRUST = trustTable();
3
+ function trustTable() {
4
+ const rows = Object.create(null);
5
+ rows.env = Object.freeze({ request: "refused" });
6
+ rows.vault = Object.freeze({ request: "own_entry" });
7
+ rows.handle = Object.freeze({ request: "refused" });
8
+ rows.assertion = Object.freeze({ request: "refused" });
9
+ return Object.freeze(rows);
10
+ }
11
+ export const CREDENTIAL_REF_TEXT_MAX = 2048;
12
+ export const CREDENTIAL_REF_MAP_MAX = 64;
13
+ export const CREDENTIAL_REF_PROBLEM_REASONS = Object.freeze(["not_a_record", "unknown_kind", "missing_field", "extra_field", "bad_value"]);
14
+ const MEMBERS = {
15
+ env: ["headers", "env"],
16
+ vault: ["entry"],
17
+ handle: ["id"],
18
+ assertion: ["audience"],
19
+ };
20
+ const TEXT_MEMBER = { vault: "entry", handle: "id", assertion: "audience" };
21
+ const HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
22
+ const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
23
+ const ECHO_MAX = 64;
24
+ const UNSAFE = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}\p{DI}\p{NChar}\p{Co}\ud800-\udfff]/u;
25
+ const UNSAFE_ALL = new RegExp(UNSAFE.source, "gu");
26
+ const ABSENT = Object.freeze({ found: "absent" });
27
+ const ACCESSOR = Object.freeze({ found: "accessor" });
28
+ const NOT_A_RECORD = Object.freeze({ ok: false, problem: Object.freeze({ reason: "not_a_record" }) });
29
+ function isRecord(value) {
30
+ if (typeof value !== "object" || value === null || Array.isArray(value))
31
+ return false;
32
+ const proto = Object.getPrototypeOf(value);
33
+ return proto === null || Object.getPrototypeOf(proto) === null;
34
+ }
35
+ function member(record, key) {
36
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
37
+ if (descriptor === undefined || descriptor.enumerable !== true)
38
+ return ABSENT;
39
+ return Object.hasOwn(descriptor, "value") ? { found: "value", value: descriptor.value } : ACCESSOR;
40
+ }
41
+ const echo = (text) => text.slice(0, ECHO_MAX).replace(UNSAFE_ALL, "?");
42
+ const refused = (problem) => Object.freeze({ ok: false, problem: Object.freeze(problem) });
43
+ const accepted = (ref) => Object.freeze({ ok: true, ref });
44
+ const isText = (value) => typeof value === "string" && value.length > 0 && value.length <= CREDENTIAL_REF_TEXT_MAX && !UNSAFE.test(value) && value === value.trim();
45
+ const isName = (value, form) => value.length <= CREDENTIAL_REF_TEXT_MAX && form.test(value);
46
+ function nameMap(value, keyForm, foldCase) {
47
+ try {
48
+ if (!isRecord(value))
49
+ return undefined;
50
+ const names = Object.keys(value);
51
+ if (names.length === 0 || names.length > CREDENTIAL_REF_MAP_MAX)
52
+ return undefined;
53
+ const out = Object.create(null);
54
+ const folded = new Set();
55
+ for (const name of names) {
56
+ const found = member(value, name);
57
+ if (found.found !== "value" || typeof found.value !== "string")
58
+ return undefined;
59
+ if (!isName(name, keyForm) || !isName(found.value, ENV_NAME))
60
+ return undefined;
61
+ if (foldCase) {
62
+ const key = name.toLowerCase();
63
+ if (folded.has(key))
64
+ return undefined;
65
+ folded.add(key);
66
+ }
67
+ out[name] = found.value;
68
+ }
69
+ return Object.freeze(out);
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
75
+ const mapOf = (found, keyForm, foldCase) => (found.found === "value" ? nameMap(found.value, keyForm, foldCase) : undefined);
76
+ function envRef(record) {
77
+ const given = { headers: member(record, "headers"), env: member(record, "env") };
78
+ if (given.headers.found === "absent" && given.env.found === "absent")
79
+ return refused({ reason: "missing_field", kind: "env", field: "headers|env" });
80
+ const headers = mapOf(given.headers, HEADER_NAME, true);
81
+ if (given.headers.found !== "absent" && headers === undefined)
82
+ return refused({ reason: "bad_value", kind: "env", field: "headers" });
83
+ const env = mapOf(given.env, ENV_NAME, false);
84
+ if (given.env.found !== "absent" && env === undefined)
85
+ return refused({ reason: "bad_value", kind: "env", field: "env" });
86
+ return accepted(Object.freeze({ kind: "env", ...(headers === undefined ? {} : { headers }), ...(env === undefined ? {} : { env }) }));
87
+ }
88
+ function read(value) {
89
+ if (!isRecord(value))
90
+ return NOT_A_RECORD;
91
+ const named = member(value, "kind");
92
+ if (named.found === "absent")
93
+ return refused({ reason: "missing_field", field: "kind" });
94
+ if (named.found !== "value" || typeof named.value !== "string")
95
+ return refused({ reason: "bad_value", field: "kind" });
96
+ const text = named.value;
97
+ const kind = CREDENTIAL_REF_KINDS.find((k) => k === text);
98
+ if (kind === undefined)
99
+ return refused({ reason: "unknown_kind", kind: echo(text) });
100
+ for (const key of Object.keys(value)) {
101
+ if (key !== "kind" && !MEMBERS[kind].includes(key))
102
+ return refused({ reason: "extra_field", kind, field: echo(key) });
103
+ }
104
+ if (kind === "env")
105
+ return envRef(value);
106
+ const field = TEXT_MEMBER[kind];
107
+ const found = member(value, field);
108
+ if (found.found === "absent")
109
+ return refused({ reason: "missing_field", kind, field });
110
+ if (found.found !== "value" || !isText(found.value))
111
+ return refused({ reason: "bad_value", kind, field });
112
+ if (kind === "vault")
113
+ return accepted(Object.freeze({ kind, entry: found.value }));
114
+ if (kind === "handle")
115
+ return accepted(Object.freeze({ kind, id: found.value }));
116
+ return accepted(Object.freeze({ kind, audience: found.value }));
117
+ }
118
+ export function readCredentialRef(value) {
119
+ try {
120
+ return read(value);
121
+ }
122
+ catch {
123
+ return NOT_A_RECORD;
124
+ }
125
+ }
@@ -0,0 +1 @@
1
+ export { CREDENTIAL_REF_KINDS, CREDENTIAL_REF_TRUST, CREDENTIAL_REF_TEXT_MAX, CREDENTIAL_REF_MAP_MAX, CREDENTIAL_REF_PROBLEM_REASONS, readCredentialRef, type CredentialRef, type CredentialRefKind, type CredentialRefRequestAdmission, type CredentialRefProblem, type CredentialRefProblemReason, type CredentialRefReading, } from "./credential-ref.js";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export { CREDENTIAL_REF_KINDS, CREDENTIAL_REF_TRUST, CREDENTIAL_REF_TEXT_MAX, CREDENTIAL_REF_MAP_MAX, CREDENTIAL_REF_PROBLEM_REASONS, readCredentialRef, } from "./credential-ref.js";
package/package.json CHANGED
@@ -1,6 +1,35 @@
1
1
  {
2
2
  "name": "@sema-agent/primitives",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "7.57.0",
4
+ "private": false,
5
+ "description": "Shared low-level definitions of the sema engine, importable by any layer: the credential reference (closed set of kinds, one reader). Zero dependencies.",
6
+ "type": "module",
7
+ "license": "BUSL-1.1",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/sema-agent/sema-core.git",
11
+ "directory": "packages/primitives"
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "sideEffects": false,
25
+ "engines": {
26
+ "node": ">=20.18.1"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "scripts": {
32
+ "build": "tsc -p tsconfig.json"
33
+ },
34
+ "gitHead": "84be0e09dcdd8e157f88f083241ceafedc0f33aa"
35
+ }