@code-yeongyu/senpi-realm-registry 0.0.0-reserve.0 → 2026.11.13

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/README.md ADDED
@@ -0,0 +1,6 @@
1
+ # @earendil-works/pi-realm-registry
2
+
3
+ One pinned, versioned registry instance per JavaScript realm (omo#12965). senpi's engine modules keep every table that one
4
+ engine copy writes and another reads behind `realmRegistry(keyName, create, isV1)`, so a second copy of the engine in
5
+ the same process shares the table instead of keeping a private one. Private workspace package; published as
6
+ `@code-yeongyu/senpi-realm-registry` with pi-ai and vendored into the engine tarball.
@@ -0,0 +1,34 @@
1
+ /**
2
+ * One registry instance per JavaScript realm, whatever number of engine copies load (omo#12965).
3
+ *
4
+ * A process can evaluate senpi's engine modules more than once (the bundled CLI next to the SDK graph a plugin imports,
5
+ * a re-evaluated extension generation, an embedder's second install). A table one copy writes and another reads must
6
+ * therefore not live in module scope. Each such table is a frozen interface object whose state lives only in the
7
+ * closure of the copy that created it, pinned on `globalThis` under `Symbol.for(keyName)` (non-writable,
8
+ * non-configurable, non-enumerable). Every later copy adopts that instance and calls through its functions: nothing
9
+ * crosses copies through class identity, and readers validate every value that does.
10
+ *
11
+ * Permanent contract: a key name never changes; its v1 members are never removed or repurposed, and later versions only
12
+ * add members, so a copy adopts any pinned, frozen object that satisfies the v1 check and ignores members it does not
13
+ * know. A slot that is not pinned that way (planted before senpi loaded, an accessor, another shape) is refused with a
14
+ * typed error that names the key and never a value. Workers, `vm` contexts and child processes are other realms and
15
+ * hold their own instances. This package holds no state of its own, so every inlined copy applies one rule.
16
+ */
17
+ export declare const REALM_REGISTRY_FOREIGN = "SENPI_REALM_REGISTRY_FOREIGN";
18
+ export declare class RealmRegistryError extends Error {
19
+ readonly code: typeof REALM_REGISTRY_FOREIGN;
20
+ readonly key: string;
21
+ constructor(keyName: string, cause?: unknown);
22
+ }
23
+ /** Builds the error a refused slot raises; the redaction registry keeps its own class and code (senpi#6334). */
24
+ export type RealmRegistryRefusal = (cause?: unknown) => Error;
25
+ /**
26
+ * The realm's single instance under `keyName`: the pinned one when it exists and satisfies `isV1`, else the frozen
27
+ * object `create()` builds, pinned now. Throws `refuse()` (by default `RealmRegistryError`) for any other slot value.
28
+ */
29
+ export declare function realmRegistry<T extends object>(keyName: string, create: () => T, isV1: (value: unknown) => value is T, refuse?: RealmRegistryRefusal): T;
30
+ /** The realm's instance under `keyName` without ever creating one: `undefined` when none exists yet. */
31
+ export declare function realmRegistryLookup<T extends object>(keyName: string, isV1: (value: unknown) => value is T, refuse?: RealmRegistryRefusal): T | undefined;
32
+ /** Whether `value` has every named member as a function, the usual v1 check. */
33
+ export declare function hasFunctions(value: unknown, names: readonly string[]): boolean;
34
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ /**
2
+ * One registry instance per JavaScript realm, whatever number of engine copies load (omo#12965).
3
+ *
4
+ * A process can evaluate senpi's engine modules more than once (the bundled CLI next to the SDK graph a plugin imports,
5
+ * a re-evaluated extension generation, an embedder's second install). A table one copy writes and another reads must
6
+ * therefore not live in module scope. Each such table is a frozen interface object whose state lives only in the
7
+ * closure of the copy that created it, pinned on `globalThis` under `Symbol.for(keyName)` (non-writable,
8
+ * non-configurable, non-enumerable). Every later copy adopts that instance and calls through its functions: nothing
9
+ * crosses copies through class identity, and readers validate every value that does.
10
+ *
11
+ * Permanent contract: a key name never changes; its v1 members are never removed or repurposed, and later versions only
12
+ * add members, so a copy adopts any pinned, frozen object that satisfies the v1 check and ignores members it does not
13
+ * know. A slot that is not pinned that way (planted before senpi loaded, an accessor, another shape) is refused with a
14
+ * typed error that names the key and never a value. Workers, `vm` contexts and child processes are other realms and
15
+ * hold their own instances. This package holds no state of its own, so every inlined copy applies one rule.
16
+ */
17
+ export const REALM_REGISTRY_FOREIGN = "SENPI_REALM_REGISTRY_FOREIGN";
18
+ export class RealmRegistryError extends Error {
19
+ constructor(keyName, cause) {
20
+ super(`The process-wide registry ${keyName} was not installed by senpi or is incompatible; restart the process.`, cause === undefined ? undefined : { cause });
21
+ this.name = "RealmRegistryError";
22
+ this.code = REALM_REGISTRY_FOREIGN;
23
+ this.key = keyName;
24
+ }
25
+ }
26
+ function foreignRegistry(keyName) {
27
+ return (cause) => new RealmRegistryError(keyName, cause);
28
+ }
29
+ function adopted(slot, isV1, refuse) {
30
+ const value = slot.value;
31
+ if (!("value" in slot) ||
32
+ slot.writable !== false ||
33
+ slot.configurable !== false ||
34
+ typeof value !== "object" ||
35
+ value === null ||
36
+ !Object.isFrozen(value) ||
37
+ !isV1(value)) {
38
+ throw refuse();
39
+ }
40
+ return value;
41
+ }
42
+ /**
43
+ * The realm's single instance under `keyName`: the pinned one when it exists and satisfies `isV1`, else the frozen
44
+ * object `create()` builds, pinned now. Throws `refuse()` (by default `RealmRegistryError`) for any other slot value.
45
+ */
46
+ export function realmRegistry(keyName, create, isV1, refuse) {
47
+ const refusal = refuse ?? foreignRegistry(keyName);
48
+ const key = Symbol.for(keyName);
49
+ const slot = Reflect.getOwnPropertyDescriptor(globalThis, key);
50
+ if (slot !== undefined)
51
+ return adopted(slot, isV1, refusal);
52
+ const instance = Object.freeze(create());
53
+ try {
54
+ Object.defineProperty(globalThis, key, {
55
+ value: instance,
56
+ writable: false,
57
+ configurable: false,
58
+ enumerable: false,
59
+ });
60
+ }
61
+ catch (error) {
62
+ throw refusal(error);
63
+ }
64
+ return instance;
65
+ }
66
+ /** The realm's instance under `keyName` without ever creating one: `undefined` when none exists yet. */
67
+ export function realmRegistryLookup(keyName, isV1, refuse) {
68
+ const slot = Reflect.getOwnPropertyDescriptor(globalThis, Symbol.for(keyName));
69
+ return slot === undefined ? undefined : adopted(slot, isV1, refuse ?? foreignRegistry(keyName));
70
+ }
71
+ /** Whether `value` has every named member as a function, the usual v1 check. */
72
+ export function hasFunctions(value, names) {
73
+ if (typeof value !== "object" || value === null)
74
+ return false;
75
+ return names.every((name) => typeof Reflect.get(value, name) === "function");
76
+ }
77
+ //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1 +1,44 @@
1
- {"name":"@code-yeongyu/senpi-realm-registry","version":"0.0.0-reserve.0","description":"Name reservation. Real versions are published by the senpi release workflow.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/code-yeongyu/senpi.git","directory":"packages/realm-registry"}}
1
+ {
2
+ "name": "@code-yeongyu/senpi-realm-registry",
3
+ "version": "2026.11.13",
4
+ "description": "One pinned, versioned registry instance per JavaScript realm, shared by every copy of senpi's engine modules",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "!dist/**/*.map",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "clean": "shx rm -rf dist",
21
+ "build": "tsc -p tsconfig.build.json",
22
+ "test": "node ../../scripts/run-tests.mjs vitest --run",
23
+ "prepublishOnly": "npm run clean && npm run build"
24
+ },
25
+ "keywords": [
26
+ "senpi",
27
+ "realm",
28
+ "registry"
29
+ ],
30
+ "author": "Earendil Works",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "git+https://github.com/code-yeongyu/senpi.git",
35
+ "directory": "packages/realm-registry"
36
+ },
37
+ "engines": {
38
+ "node": ">=22.19.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "26.6.2",
42
+ "vitest": "5.0.1"
43
+ }
44
+ }