@jini-ai/core 0.6.15-rc.1 → 0.6.15-rc.2
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 +1 -0
- package/dist/records.d.ts +29 -6
- package/dist/records.js +105 -15
- package/dist/settings/dictionaries/index.d.ts +0 -22
- package/dist/settings/dictionaries/index.js +0 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -100,6 +100,7 @@ Tool handlers receive required execution context first and optional `{ emitSurfa
|
|
|
100
100
|
| subpath | what's behind it |
|
|
101
101
|
|---|---|
|
|
102
102
|
| `./fetch` | Framework-neutral query contracts and `FetchQueryCache`; inject transport callbacks, `Clock`, scheduler and connectivity/focus ports. No React, DOM or TanStack dependency. |
|
|
103
|
+
| `./records` | `canonicalJson({ value })`, async WebCrypto `canonicalArgumentDigest({ args }, { crypto? })`, and `CanonicalJsonError`; recursively sorted Unicode code-point keys, strict JSON validation, and lowercase SHA-256 hex. |
|
|
103
104
|
| `.` | The public surface above: tokens, packs, daemon composition, tool registry (descriptors only), principal, redact, auth primitives. |
|
|
104
105
|
| `./composition` | **Not part of the public contract.** Exposes `authorizeToolInvocation` (resolves a registry's tool and runs its authorization gate — a security-sensitive value export, but one that only ever hands back a handler alongside an `'allow'` decision) plus type-only `AnyPack`/`RequiredTokenIds`/`MissingTokenIds` re-derivation helpers. Its sole intended consumers are `@jini-ai/daemon`'s `ToolExecutor` and `@jini-ai/server`'s `createLocalNodeDaemon`. Node's resolver will happily let any consumer import it — the boundary is enforced by `scripts/check-engine-boundaries.ts`, not by the exports map — so external adopters should treat it as off-limits regardless. |
|
|
105
106
|
|
package/dist/records.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @file
|
|
1
|
+
/** @file Object-shape predicates and canonical JSON shared by tool readers and request digests. */
|
|
2
2
|
/** Accept any non-null object, including arrays; never sanitizes or reads properties.
|
|
3
3
|
* @complexity O(1) time and space.
|
|
4
4
|
* @example isRecord({ value: [] }); // true
|
|
@@ -45,14 +45,37 @@ export declare function deleteMapRecord<Key, Row extends object>({ records, key,
|
|
|
45
45
|
key: Key;
|
|
46
46
|
fields: Partial<Row>;
|
|
47
47
|
}, _optional?: Record<string, never>): void;
|
|
48
|
+
/** Invalid canonical JSON input. Messages never include argument contents. */
|
|
49
|
+
export declare class CanonicalJsonError extends TypeError {
|
|
50
|
+
constructor(required: {
|
|
51
|
+
readonly message: string;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
48
54
|
/**
|
|
49
|
-
* Canonical JSON: object keys
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* @
|
|
55
|
+
* Canonical JSON: recursively sort object keys by Unicode code point, omit undefined object
|
|
56
|
+
* properties, and preserve array order. Uses JSON scalar escaping without invoking toJSON hooks.
|
|
57
|
+
* @param required.value JSON input; shared references are allowed. Does not mutate input.
|
|
58
|
+
* @throws CanonicalJsonError for non-JSON values (including array holes) and cycles.
|
|
59
|
+
* @complexity O(s + sum(k log k * l)) time for s output bytes, k keys per object and key length l;
|
|
60
|
+
* O(s * d) worst-case space for nesting depth d, including intermediate strings and recursion.
|
|
53
61
|
* @example canonicalJson({ value: { b: 1, a: 2 } }); // '{"a":2,"b":1}'
|
|
54
62
|
*/
|
|
55
63
|
export declare function canonicalJson(required: {
|
|
56
64
|
readonly value: unknown;
|
|
57
|
-
}, _optional?:
|
|
65
|
+
}, _optional?: Record<string, never>): string;
|
|
66
|
+
/**
|
|
67
|
+
* SHA-256 lowercase hex over canonical UTF-8 tool arguments, shared by plugins and host gates.
|
|
68
|
+
* @param required.args JSON arguments; validation completes before hashing starts.
|
|
69
|
+
* @param optional.crypto Host WebCrypto port; defaults to the runtime's global WebCrypto.
|
|
70
|
+
* @returns An asynchronous digest, usable in browsers and Node without Node imports.
|
|
71
|
+
* @throws CanonicalJsonError for invalid arguments; WebCrypto failures propagate.
|
|
72
|
+
* @complexity Canonical serialization cost plus O(s) hashing time and space for s UTF-8 bytes.
|
|
73
|
+
*/
|
|
74
|
+
export declare function canonicalArgumentDigest(required: {
|
|
75
|
+
readonly args: unknown;
|
|
76
|
+
}, { crypto }?: {
|
|
77
|
+
readonly crypto?: {
|
|
78
|
+
readonly subtle: Pick<typeof globalThis.crypto.subtle, 'digest'>;
|
|
79
|
+
};
|
|
80
|
+
}): Promise<string>;
|
|
58
81
|
//# sourceMappingURL=records.d.ts.map
|
package/dist/records.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @file
|
|
1
|
+
/** @file Object-shape predicates and canonical JSON shared by tool readers and request digests. */
|
|
2
2
|
/** Accept any non-null object, including arrays; never sanitizes or reads properties.
|
|
3
3
|
* @complexity O(1) time and space.
|
|
4
4
|
* @example isRecord({ value: [] }); // true
|
|
@@ -43,23 +43,113 @@ export function deleteMapRecord({ records, key, fields }, _optional = {}) {
|
|
|
43
43
|
if (record && matchesRecordFields({ record, fields }))
|
|
44
44
|
records.delete(key);
|
|
45
45
|
}
|
|
46
|
+
/** Invalid canonical JSON input. Messages never include argument contents. */
|
|
47
|
+
export class CanonicalJsonError extends TypeError {
|
|
48
|
+
constructor(required) {
|
|
49
|
+
super(required.message);
|
|
50
|
+
this.name = 'CanonicalJsonError';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Compare Unicode code points, including astral characters; UTF-16 sort differs above U+FFFF.
|
|
54
|
+
* @complexity O(l) time and space for the combined key length l.
|
|
55
|
+
*/
|
|
56
|
+
function compareJsonKeys(left, right) {
|
|
57
|
+
const a = Array.from(left);
|
|
58
|
+
const b = Array.from(right);
|
|
59
|
+
for (let index = 0; index < Math.min(a.length, b.length); index++) {
|
|
60
|
+
const difference = a[index].codePointAt(0) - b[index].codePointAt(0);
|
|
61
|
+
if (difference !== 0)
|
|
62
|
+
return difference;
|
|
63
|
+
}
|
|
64
|
+
return a.length - b.length;
|
|
65
|
+
}
|
|
66
|
+
/** Serialize JSON scalars without JSON.stringify's lossy non-JSON fallbacks.
|
|
67
|
+
* @throws CanonicalJsonError for unsupported types or non-finite numbers.
|
|
68
|
+
* @complexity O(s) time and space for s serialized characters.
|
|
69
|
+
*/
|
|
70
|
+
function canonicalScalar(value) {
|
|
71
|
+
switch (typeof value) {
|
|
72
|
+
case 'string':
|
|
73
|
+
case 'boolean':
|
|
74
|
+
return JSON.stringify(value);
|
|
75
|
+
case 'number':
|
|
76
|
+
if (Number.isFinite(value))
|
|
77
|
+
return JSON.stringify(value);
|
|
78
|
+
throw new CanonicalJsonError({ message: 'Canonical JSON requires finite numbers.' });
|
|
79
|
+
default:
|
|
80
|
+
throw new CanonicalJsonError({ message: 'Canonical JSON requires JSON values.' });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** Serialize own enumerable JSON fields; class instances must not silently collapse to {}.
|
|
84
|
+
* @throws CanonicalJsonError for non-JSON objects or enumerable symbol keys.
|
|
85
|
+
* @complexity O(k log k * l + s) time and O(s + k * l) space, plus recursive children.
|
|
86
|
+
*/
|
|
87
|
+
function canonicalObject(value, ancestors) {
|
|
88
|
+
const prototype = Object.getPrototypeOf(value);
|
|
89
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
90
|
+
throw new CanonicalJsonError({ message: 'Canonical JSON requires plain objects or arrays.' });
|
|
91
|
+
}
|
|
92
|
+
if (Object.getOwnPropertySymbols(value).some(key => Object.prototype.propertyIsEnumerable.call(value, key))) {
|
|
93
|
+
throw new CanonicalJsonError({ message: 'Canonical JSON requires string object keys.' });
|
|
94
|
+
}
|
|
95
|
+
const record = value;
|
|
96
|
+
// Object keys are unique, so comparing their code points gives a total order here.
|
|
97
|
+
const members = Object.keys(record).sort(compareJsonKeys).flatMap(key => {
|
|
98
|
+
const child = record[key];
|
|
99
|
+
if (child === undefined)
|
|
100
|
+
return [];
|
|
101
|
+
return [`${JSON.stringify(key)}:${canonicalValue(child, ancestors)}`];
|
|
102
|
+
});
|
|
103
|
+
return `{${members.join(',')}}`;
|
|
104
|
+
}
|
|
105
|
+
/** Track only active ancestors: repeated references are JSON, back-edges are cycles.
|
|
106
|
+
* @throws CanonicalJsonError for cycles or non-JSON children.
|
|
107
|
+
* @complexity O(s + sum(k log k * l)) time; O(s * d) worst-case space for depth d.
|
|
108
|
+
*/
|
|
109
|
+
function canonicalValue(value, ancestors) {
|
|
110
|
+
if (value === null)
|
|
111
|
+
return 'null';
|
|
112
|
+
if (typeof value !== 'object')
|
|
113
|
+
return canonicalScalar(value);
|
|
114
|
+
if (ancestors.has(value))
|
|
115
|
+
throw new CanonicalJsonError({ message: 'Canonical JSON does not support cycles.' });
|
|
116
|
+
ancestors.add(value);
|
|
117
|
+
try {
|
|
118
|
+
if (!Array.isArray(value))
|
|
119
|
+
return canonicalObject(value, ancestors);
|
|
120
|
+
// Read every index: holes must fail, and a custom iterator must not change the argument order.
|
|
121
|
+
const children = [];
|
|
122
|
+
for (let index = 0; index < value.length; index++)
|
|
123
|
+
children.push(canonicalValue(value[index], ancestors));
|
|
124
|
+
return `[${children.join(',')}]`;
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
ancestors.delete(value);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
46
130
|
/**
|
|
47
|
-
* Canonical JSON: object keys
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* @
|
|
131
|
+
* Canonical JSON: recursively sort object keys by Unicode code point, omit undefined object
|
|
132
|
+
* properties, and preserve array order. Uses JSON scalar escaping without invoking toJSON hooks.
|
|
133
|
+
* @param required.value JSON input; shared references are allowed. Does not mutate input.
|
|
134
|
+
* @throws CanonicalJsonError for non-JSON values (including array holes) and cycles.
|
|
135
|
+
* @complexity O(s + sum(k log k * l)) time for s output bytes, k keys per object and key length l;
|
|
136
|
+
* O(s * d) worst-case space for nesting depth d, including intermediate strings and recursion.
|
|
51
137
|
* @example canonicalJson({ value: { b: 1, a: 2 } }); // '{"a":2,"b":1}'
|
|
52
138
|
*/
|
|
53
139
|
export function canonicalJson(required, _optional = {}) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
140
|
+
return canonicalValue(required.value, new Set());
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* SHA-256 lowercase hex over canonical UTF-8 tool arguments, shared by plugins and host gates.
|
|
144
|
+
* @param required.args JSON arguments; validation completes before hashing starts.
|
|
145
|
+
* @param optional.crypto Host WebCrypto port; defaults to the runtime's global WebCrypto.
|
|
146
|
+
* @returns An asynchronous digest, usable in browsers and Node without Node imports.
|
|
147
|
+
* @throws CanonicalJsonError for invalid arguments; WebCrypto failures propagate.
|
|
148
|
+
* @complexity Canonical serialization cost plus O(s) hashing time and space for s UTF-8 bytes.
|
|
149
|
+
*/
|
|
150
|
+
export async function canonicalArgumentDigest(required, { crypto = globalThis.crypto } = {}) {
|
|
151
|
+
const json = canonicalJson({ value: required.args });
|
|
152
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(json));
|
|
153
|
+
return Array.from(new Uint8Array(digest), byte => byte.toString(16).padStart(2, '0')).join('');
|
|
64
154
|
}
|
|
65
155
|
//# sourceMappingURL=records.js.map
|
|
@@ -14,28 +14,6 @@
|
|
|
14
14
|
* IS the key" — `translateSettingsDialog` falls back to the raw key for English and any
|
|
15
15
|
* unrecognized locale.
|
|
16
16
|
*/
|
|
17
|
-
import { SETTINGS_DIALOG_ES } from './settings-dialog.es.js';
|
|
18
|
-
import { SETTINGS_DIALOG_ID } from './settings-dialog.id.js';
|
|
19
|
-
import { SETTINGS_DIALOG_DE } from './settings-dialog.de.js';
|
|
20
|
-
import { SETTINGS_DIALOG_ZH_CN } from './settings-dialog.zh-CN.js';
|
|
21
|
-
import { SETTINGS_DIALOG_ZH_TW } from './settings-dialog.zh-TW.js';
|
|
22
|
-
import { SETTINGS_DIALOG_PT_BR } from './settings-dialog.pt-BR.js';
|
|
23
|
-
import { SETTINGS_DIALOG_RU } from './settings-dialog.ru.js';
|
|
24
|
-
import { SETTINGS_DIALOG_FA } from './settings-dialog.fa.js';
|
|
25
|
-
import { SETTINGS_DIALOG_AR } from './settings-dialog.ar.js';
|
|
26
|
-
import { SETTINGS_DIALOG_JA } from './settings-dialog.ja.js';
|
|
27
|
-
import { SETTINGS_DIALOG_KO } from './settings-dialog.ko.js';
|
|
28
|
-
import { SETTINGS_DIALOG_PL } from './settings-dialog.pl.js';
|
|
29
|
-
import { SETTINGS_DIALOG_HU } from './settings-dialog.hu.js';
|
|
30
|
-
import { SETTINGS_DIALOG_FR } from './settings-dialog.fr.js';
|
|
31
|
-
import { SETTINGS_DIALOG_UK } from './settings-dialog.uk.js';
|
|
32
|
-
import { SETTINGS_DIALOG_TR } from './settings-dialog.tr.js';
|
|
33
|
-
import { SETTINGS_DIALOG_TH } from './settings-dialog.th.js';
|
|
34
|
-
import { SETTINGS_DIALOG_IT } from './settings-dialog.it.js';
|
|
35
|
-
import { SETTINGS_DIALOG_HI } from './settings-dialog.hi.js';
|
|
36
|
-
import { SETTINGS_DIALOG_UR } from './settings-dialog.ur.js';
|
|
37
|
-
import { SETTINGS_DIALOG_BN } from './settings-dialog.bn.js';
|
|
38
|
-
export { SETTINGS_DIALOG_ES, SETTINGS_DIALOG_ID, SETTINGS_DIALOG_DE, SETTINGS_DIALOG_ZH_CN, SETTINGS_DIALOG_ZH_TW, SETTINGS_DIALOG_PT_BR, SETTINGS_DIALOG_RU, SETTINGS_DIALOG_FA, SETTINGS_DIALOG_AR, SETTINGS_DIALOG_JA, SETTINGS_DIALOG_KO, SETTINGS_DIALOG_PL, SETTINGS_DIALOG_HU, SETTINGS_DIALOG_FR, SETTINGS_DIALOG_UK, SETTINGS_DIALOG_TR, SETTINGS_DIALOG_TH, SETTINGS_DIALOG_IT, SETTINGS_DIALOG_HI, SETTINGS_DIALOG_UR, SETTINGS_DIALOG_BN, };
|
|
39
17
|
/** Every non-English locale this dictionary covers, keyed the same way `@jini-ai/ui`'s
|
|
40
18
|
* `SETTINGS_DIALOG_DICTIONARIES` is. */
|
|
41
19
|
export declare const SETTINGS_DIALOG_DICTIONARIES: Readonly<Record<string, Record<string, string>>>;
|
|
@@ -35,7 +35,6 @@ import { SETTINGS_DIALOG_IT } from './settings-dialog.it.js';
|
|
|
35
35
|
import { SETTINGS_DIALOG_HI } from './settings-dialog.hi.js';
|
|
36
36
|
import { SETTINGS_DIALOG_UR } from './settings-dialog.ur.js';
|
|
37
37
|
import { SETTINGS_DIALOG_BN } from './settings-dialog.bn.js';
|
|
38
|
-
export { SETTINGS_DIALOG_ES, SETTINGS_DIALOG_ID, SETTINGS_DIALOG_DE, SETTINGS_DIALOG_ZH_CN, SETTINGS_DIALOG_ZH_TW, SETTINGS_DIALOG_PT_BR, SETTINGS_DIALOG_RU, SETTINGS_DIALOG_FA, SETTINGS_DIALOG_AR, SETTINGS_DIALOG_JA, SETTINGS_DIALOG_KO, SETTINGS_DIALOG_PL, SETTINGS_DIALOG_HU, SETTINGS_DIALOG_FR, SETTINGS_DIALOG_UK, SETTINGS_DIALOG_TR, SETTINGS_DIALOG_TH, SETTINGS_DIALOG_IT, SETTINGS_DIALOG_HI, SETTINGS_DIALOG_UR, SETTINGS_DIALOG_BN, };
|
|
39
38
|
/** Every non-English locale this dictionary covers, keyed the same way `@jini-ai/ui`'s
|
|
40
39
|
* `SETTINGS_DIALOG_DICTIONARIES` is. */
|
|
41
40
|
export const SETTINGS_DIALOG_DICTIONARIES = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/core",
|
|
3
|
-
"version": "0.6.15-rc.
|
|
3
|
+
"version": "0.6.15-rc.2",
|
|
4
4
|
"description": "The Jini kernel: typed DI tokens, pack composition and lifecycle, the tool registry, redaction, and origin/API-token auth primitives. Zero dependencies.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|