@jini-ai/core 0.4.9 → 0.6.10

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @jini-ai/core
2
2
 
3
+ ## 0.6.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 22f0619: Export baseline agent-failure token patterns, credential-directory deny
8
+ segments, and local-owner proxy markers for reuse by consumers.
9
+ Preserve existing vocabulary and redaction behavior.
10
+ - 82ed2d3: Expose the React-free fetch-query contracts/cache at @jini-ai/core/fetch; UI keeps deprecated direct type re-exports. Build core before UI and publish before consumers adopt the subpath.
11
+ - 5a3de86: Add optional `expectedRevisionSeq` options to settings `set(required, options)` and
12
+ `clear(required, options)`. Compare the addressed scope's stored value revision under
13
+ the existing transaction's ledger lock, throwing `SettingsRevisionConflictError`
14
+ with expected and actual sequences on mismatch and rolling back the write and revision.
15
+ Revision 0 represents a missing row; cleared rows retain their revision. Omitting
16
+ the option preserves unconditional writes. Available through `@jini-ai/core/settings`
17
+ and the existing `@jini-ai/cms/settings` compatibility re-export.
18
+
3
19
  ## 0.4.9 — 2026-10-22
4
20
 
5
21
  - 2026-10-22: Provider registry, ObjectStore contract with object_store registry and deferObjectStore, default-on batch tool eligibility, coverage.
@@ -56,7 +72,6 @@
56
72
  - Move the domain-independent catalog/input/schema/risk/confirmation registration kit into the root entry, with its behavior contracts. Domain-specific authorization and denial errors remain outside the kernel.
57
73
  - Use the existing named argument surface directly; primitive, Result and tool catalog types remain canonical in core.
58
74
 
59
-
60
75
  ### Shared kernel
61
76
 
62
77
  - Add `./primitives` with canonical time, ID, JSON, HTTP, logger and result contracts,
@@ -80,7 +95,6 @@
80
95
  - Origin diagnostics use `Pick<Logger, 'warn'>` rather than a duplicate logger interface.
81
96
  The alias name `OriginValidationLoggerPort` remains available with the shared shape.
82
97
 
83
-
84
98
  - Add transport-neutral gated mutations with required token generation/TTL and async
85
99
  authorization, identity and token-store ports; preserve verified-plan handoff and
86
100
  single-use redemption, with atomic explicit expiry and duplicate-issuance rejection.
package/README.md CHANGED
@@ -44,6 +44,11 @@ peer used only by `@jini-ai/core/settings/express`; install it in hosts mounting
44
44
 
45
45
  ## Usage
46
46
 
47
+ The root exports baseline security vocabulary: `AGENT_FAILURE_SECRET_SHAPE_RE`,
48
+ `CREDENTIAL_FILE_DENY_SEGMENTS`, `LOCAL_OWNER_PROXY_MARKER_PREFIXES`, and
49
+ `LOCAL_OWNER_PROXY_MARKER_HEADERS`. Consumers apply these in their existing failure-redaction,
50
+ guarded-file, and local-owner admission policies; the existing redactors are unchanged.
51
+
47
52
  ```ts
48
53
  import { bindings, definePack, createDaemon, token, createToolRegistry, registerPackTools } from '@jini-ai/core';
49
54
 
package/dist/redact.d.ts CHANGED
@@ -38,6 +38,34 @@ export interface SecretShapePattern {
38
38
  }
39
39
  export declare const PEM_PATTERN_NAME = "PEM private key block";
40
40
  export declare const SECRET_SHAPE_PATTERNS: readonly SecretShapePattern[];
41
+ /** Broad token shapes for agent-failure text; consumers retain their plain [REDACTED] pipeline. */
42
+ export declare const AGENT_FAILURE_SECRET_SHAPE_RE: RegExp;
43
+ /**
44
+ * Exact path SEGMENT names refused at any depth, matched case-insensitively against each segment
45
+ * of the caller-supplied path (never a substring — a directory named `not-secrets-actually` is not
46
+ * a match). `secrets` is the owner's explicit example: whatever a site or app tree names its
47
+ * credentials folder (`sites/**\/secrets/`, `apps/admin/**\/secrets/`, or anywhere else), it never
48
+ * becomes reachable through this domain. A denied segment is refused by the guarded reader
49
+ * AND skipped entirely by the `fs_list_files` walk — its contents are never even enumerated,
50
+ * not merely refused once named. Besides `secrets`, the set names the
51
+ * well-known credential-store directories a home-directory `custom` root can expose: `.aws`
52
+ * (`credentials`), `.docker` (`config.json` with registry auth), `.kube` (`config`), and
53
+ * `gcloud`/`gh` for `.config/gcloud/application_default_credentials.json` and
54
+ * `.config/gh/hosts.yml`. Denied by SEGMENT rather than by leaf filename on purpose: `config`,
55
+ * `config.json`, and `hosts.yml` are generic names that appear harmlessly elsewhere, so denying the
56
+ * directory is the narrower of the two mistakes.
57
+ *
58
+ * A host's install-wide site-key directory (2026-09-24) needs the same protection; the host appends it.
59
+ * Production stores it beside individual site folders on a durable volume; local/dev stores
60
+ * it below the home directory, reachable through an operator-set `custom` root. Its key backs
61
+ * site-key administration, webhook/newsletter signing secrets, and permission checks, so the
62
+ * agent must never read it from disk. Denying the whole directory segment, rather than only
63
+ * a generated key filename, also prevents `fs_list_files` from enumerating its contents — the
64
+ * same "never even advertise it" property `secrets` gets above.
65
+ */
66
+ export declare const CREDENTIAL_FILE_DENY_SEGMENTS: readonly string[];
67
+ export declare const LOCAL_OWNER_PROXY_MARKER_PREFIXES: readonly string[];
68
+ export declare const LOCAL_OWNER_PROXY_MARKER_HEADERS: readonly string[];
41
69
  export interface SecretRedactionPattern {
42
70
  name: string;
43
71
  regex: RegExp;
package/dist/redact.js CHANGED
@@ -52,6 +52,40 @@ export const SECRET_SHAPE_PATTERNS = [
52
52
  { name: "Fastmail app password (fm2_)", pattern: /(?<![A-Za-z0-9+/=])fm2_[A-Za-z0-9+/=]{20,}/ },
53
53
  { name: PEM_PATTERN_NAME, pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
54
54
  ];
55
+ /** Broad token shapes for agent-failure text; consumers retain their plain [REDACTED] pipeline. */
56
+ export const AGENT_FAILURE_SECRET_SHAPE_RE = /\b(?:AIza[\w-]+|AQ\.[\w.\/-]+|sk-[\w.-]+|gh[pousr]_[\w]+|github_pat_[\w]+|ya29\.[\w.-]+|eyJ[\w-]+\.[\w-]+(?:\.[\w-]+)?)/g;
57
+ /**
58
+ * Exact path SEGMENT names refused at any depth, matched case-insensitively against each segment
59
+ * of the caller-supplied path (never a substring — a directory named `not-secrets-actually` is not
60
+ * a match). `secrets` is the owner's explicit example: whatever a site or app tree names its
61
+ * credentials folder (`sites/**\/secrets/`, `apps/admin/**\/secrets/`, or anywhere else), it never
62
+ * becomes reachable through this domain. A denied segment is refused by the guarded reader
63
+ * AND skipped entirely by the `fs_list_files` walk — its contents are never even enumerated,
64
+ * not merely refused once named. Besides `secrets`, the set names the
65
+ * well-known credential-store directories a home-directory `custom` root can expose: `.aws`
66
+ * (`credentials`), `.docker` (`config.json` with registry auth), `.kube` (`config`), and
67
+ * `gcloud`/`gh` for `.config/gcloud/application_default_credentials.json` and
68
+ * `.config/gh/hosts.yml`. Denied by SEGMENT rather than by leaf filename on purpose: `config`,
69
+ * `config.json`, and `hosts.yml` are generic names that appear harmlessly elsewhere, so denying the
70
+ * directory is the narrower of the two mistakes.
71
+ *
72
+ * A host's install-wide site-key directory (2026-09-24) needs the same protection; the host appends it.
73
+ * Production stores it beside individual site folders on a durable volume; local/dev stores
74
+ * it below the home directory, reachable through an operator-set `custom` root. Its key backs
75
+ * site-key administration, webhook/newsletter signing secrets, and permission checks, so the
76
+ * agent must never read it from disk. Denying the whole directory segment, rather than only
77
+ * a generated key filename, also prevents `fs_list_files` from enumerating its contents — the
78
+ * same "never even advertise it" property `secrets` gets above.
79
+ */
80
+ // Generic credential-store segments only. A host adds its own product-specific key directory
81
+ // (e.g. its install-wide site-key folder) when it builds its deny-list; core stays product-neutral.
82
+ export const CREDENTIAL_FILE_DENY_SEGMENTS = ["secrets", ".aws", ".docker", ".kube", "gcloud", "gh"];
83
+ // A local tunnel has a loopback socket and may rewrite Host; refuse marker presence, even empty.
84
+ export const LOCAL_OWNER_PROXY_MARKER_PREFIXES = ["x-forwarded-", "x-envoy-", "x-ms-"];
85
+ export const LOCAL_OWNER_PROXY_MARKER_HEADERS = [
86
+ "forwarded", "x-real-ip", "via", "cf-connecting-ip", "true-client-ip", "x-original-host",
87
+ "x-client-ip", "x-cluster-client-ip", "fastly-client-ip", "tailscale-user-login", "x-original-forwarded-for",
88
+ ];
55
89
  // Order matters: list specific rules before more general ones. Langfuse
56
90
  // keys (`sk-lf-...`) would otherwise be eaten by the generic `sk-...`
57
91
  // rule and labeled as a generic OpenAI-style key.
@@ -18,6 +18,19 @@ export declare class SecretNotSupportedError extends Error {
18
18
  }
19
19
  export declare class ValueValidationFailedError extends Error {
20
20
  }
21
+ /**
22
+ * A scoped value changed since the caller's snapshot; read again before retrying.
23
+ * Both sequences refer to the addressed value row, never the ledger's global watermark.
24
+ * @example if (error instanceof SettingsRevisionConflictError) await refreshSnapshot();
25
+ */
26
+ export declare class SettingsRevisionConflictError extends Error {
27
+ readonly expectedRevisionSeq: number;
28
+ readonly actualRevisionSeq: number;
29
+ constructor(required: {
30
+ expectedRevisionSeq: number;
31
+ actualRevisionSeq: number;
32
+ }, optional?: ErrorOptions);
33
+ }
21
34
  export declare class RenameRetypeConflictError extends Error {
22
35
  }
23
36
  export declare class AliasDepthExceededError extends Error {
@@ -18,6 +18,21 @@ export class SecretNotSupportedError extends Error {
18
18
  }
19
19
  export class ValueValidationFailedError extends Error {
20
20
  }
21
+ /**
22
+ * A scoped value changed since the caller's snapshot; read again before retrying.
23
+ * Both sequences refer to the addressed value row, never the ledger's global watermark.
24
+ * @example if (error instanceof SettingsRevisionConflictError) await refreshSnapshot();
25
+ */
26
+ export class SettingsRevisionConflictError extends Error {
27
+ expectedRevisionSeq;
28
+ actualRevisionSeq;
29
+ constructor(required, optional = {}) {
30
+ super(`Setting revision changed: expected ${required.expectedRevisionSeq}, found ${required.actualRevisionSeq}.`, optional);
31
+ this.name = "SettingsRevisionConflictError";
32
+ this.expectedRevisionSeq = required.expectedRevisionSeq;
33
+ this.actualRevisionSeq = required.actualRevisionSeq;
34
+ }
35
+ }
21
36
  export class RenameRetypeConflictError extends Error {
22
37
  }
23
38
  export class AliasDepthExceededError extends Error {
@@ -11,11 +11,11 @@
11
11
  * `SettingsRepoPort` this barrel exports.
12
12
  */
13
13
  export { SCOPE_BIT, type SettingScope, type SettingOwnerKind, type DefinitionStatus, type ValueState, type RevisionEntityKind, type RevisionOp, type SettingValueSchema, type SettingDefinitionRecord, type SettingValueRecord, type SettingRevisionRecord, type SettingScopeContext, } from "./types.js";
14
- export { DefinitionInvalidError, ScopeNotAllowedError, SecretNotSupportedError, ValueValidationFailedError, RenameRetypeConflictError, AliasDepthExceededError, DefinitionTombstonedError, DefinitionNotFoundError, PurgeRequiredError, ForbiddenError, PrincipalNotFoundError, } from "./errors.js";
14
+ export { DefinitionInvalidError, ScopeNotAllowedError, SecretNotSupportedError, ValueValidationFailedError, SettingsRevisionConflictError, RenameRetypeConflictError, AliasDepthExceededError, DefinitionTombstonedError, DefinitionNotFoundError, PurgeRequiredError, ForbiddenError, PrincipalNotFoundError, } from "./errors.js";
15
15
  export type { SettingsRepoPort } from "./ports.js";
16
16
  export { InMemorySettingsRepo } from "./repo.memory.js";
17
17
  export { type DefinitionInput, validateDefinitionInput, validateValueAgainstSchema, registerCoercer, invalidateDefinitionNamespaceCache, invalidateWorkspaceSettingsCache, resolveDefinitionRaw, resolveDefinition, type ResolvedSetting, getEffective, } from "./settings.js";
18
- export { type AuthorizeFn, type SettingsWriteServiceDeps, deriveRequiredPermission, type RegisterDefinitionsRequired, registerDefinitions, type SetValueRequired, set, type ClearValueRequired, clear, type ResetNamespaceRequired, resetNamespace, type RenameDefinitionRequired, renameDefinition, type RetypeDefinitionRequired, retypeDefinition, type ReconcileDefinitionDefaultRequired, reconcileDefinitionDefault, type DeprecateDefinitionRequired, deprecateDefinition, type TombstoneDefinitionRequired, tombstoneDefinition, } from "./write-service.js";
18
+ export { type AuthorizeFn, type SettingsWriteServiceDeps, deriveRequiredPermission, type RegisterDefinitionsRequired, registerDefinitions, type SetValueRequired, type SettingsValueWriteOptions, set, type ClearValueRequired, clear, type ResetNamespaceRequired, resetNamespace, type RenameDefinitionRequired, renameDefinition, type RetypeDefinitionRequired, retypeDefinition, type ReconcileDefinitionDefaultRequired, reconcileDefinitionDefault, type DeprecateDefinitionRequired, deprecateDefinition, type TombstoneDefinitionRequired, tombstoneDefinition, } from "./write-service.js";
19
19
  export { type PurgeServiceDeps, type PurgeTenantSettingsRequired, purgeTenantSettings, } from "./purge-service.js";
20
20
  export { type ChangeFeedViewer, isRevisionVisibleTo, type ChangeFeedBatch, collectChangedNamespaces, } from "./change-feed.js";
21
21
  export { type DefinitionOpRequestItem, type DefinitionOpContext, type DefinitionOpHandler, NON_REGISTER_DEFINITION_OP_NAMES, type NonRegisterDefinitionOp, parseNonRegisterDefinitionOp, NON_REGISTER_DEFINITION_OPS, } from "./definitions-dispatch.js";
@@ -11,7 +11,7 @@
11
11
  * `SettingsRepoPort` this barrel exports.
12
12
  */
13
13
  export { SCOPE_BIT, } from "./types.js";
14
- export { DefinitionInvalidError, ScopeNotAllowedError, SecretNotSupportedError, ValueValidationFailedError, RenameRetypeConflictError, AliasDepthExceededError, DefinitionTombstonedError, DefinitionNotFoundError, PurgeRequiredError, ForbiddenError, PrincipalNotFoundError, } from "./errors.js";
14
+ export { DefinitionInvalidError, ScopeNotAllowedError, SecretNotSupportedError, ValueValidationFailedError, SettingsRevisionConflictError, RenameRetypeConflictError, AliasDepthExceededError, DefinitionTombstonedError, DefinitionNotFoundError, PurgeRequiredError, ForbiddenError, PrincipalNotFoundError, } from "./errors.js";
15
15
  export { InMemorySettingsRepo } from "./repo.memory.js";
16
16
  export { validateDefinitionInput, validateValueAgainstSchema, registerCoercer, invalidateDefinitionNamespaceCache, invalidateWorkspaceSettingsCache, resolveDefinitionRaw, resolveDefinition, getEffective, } from "./settings.js";
17
17
  export { deriveRequiredPermission, registerDefinitions, set, clear, resetNamespace, renameDefinition, retypeDefinition, reconcileDefinitionDefault, deprecateDefinition, tombstoneDefinition, } from "./write-service.js";
@@ -68,7 +68,13 @@ export interface SettingsRepoPort {
68
68
  principalId: UUID;
69
69
  settingId: UUID;
70
70
  }): Promise<void>;
71
- /** Appends a revision and returns its assigned `seq` (used to stamp the paired value row). */
71
+ /**
72
+ * Appends a revision and returns its assigned `seq` (used to stamp the paired value row).
73
+ * Inside a transaction, serialize revision writers until that enclosing transaction ends:
74
+ * `set`/`clear` compare the stored value's seq AFTER this call, so the lock must cover the
75
+ * comparison and value save too. SQLite's write transaction and Postgres's transaction-scoped
76
+ * ledger lock provide this; memory refuses overlapping transactions.
77
+ */
72
78
  appendRevision(record: Omit<SettingRevisionRecord, "seq">): Promise<number>;
73
79
  listRevisions(required: {
74
80
  settingId: UUID;
@@ -110,8 +110,21 @@ export interface SetValueRequired {
110
110
  requiredPermissionOverride?: string | undefined;
111
111
  };
112
112
  }
113
- /** chokepoint write: authorize -> validate -> value + revision, same tx. See docs/decisions/DR-003-settings-ledger-invariants.md. */
114
- export declare function set(required: SetValueRequired): Promise<{
113
+ /** Optional concurrency guard shared by `set` and `clear`. */
114
+ export interface SettingsValueWriteOptions {
115
+ /** Compare the addressed layer's stored seq, including cleared rows; 0 means no stored row.
116
+ * Omission preserves unconditional writes. Defaults, inherited values and definition revisions
117
+ * do not count. A mismatch throws SettingsRevisionConflictError and rolls back the write.
118
+ */
119
+ readonly expectedRevisionSeq?: number | undefined;
120
+ }
121
+ /**
122
+ * Authorize -> validate -> value + revision in one transaction. An optional expectedRevisionSeq
123
+ * refuses a stale scoped value and rolls back its revision; omission keeps unconditional writes.
124
+ * @example await set({ deps, input }, { expectedRevisionSeq: snapshotSeq });
125
+ * See docs/decisions/DR-003-settings-ledger-invariants.md.
126
+ */
127
+ export declare function set(required: SetValueRequired, optional?: SettingsValueWriteOptions): Promise<{
115
128
  value: JsonValue;
116
129
  revisionSeq: number;
117
130
  }>;
@@ -135,8 +148,14 @@ export interface ClearValueRequired {
135
148
  authWorkspaceId?: UUID | undefined;
136
149
  };
137
150
  }
138
- /** chokepoint write: authorize -> value + revision (state='cleared'), same tx. See docs/decisions/DR-003-settings-ledger-invariants.md. */
139
- export declare function clear(required: ClearValueRequired): Promise<{
151
+ /**
152
+ * Authorize -> cleared value + revision in one transaction; the optional concurrency guard has
153
+ * the same semantics as `set`. With skipTransaction, the enclosing caller must propagate errors
154
+ * so its transaction rolls back the appended revision on conflict.
155
+ * @example await clear({ deps, input }, { expectedRevisionSeq: snapshotSeq });
156
+ * See docs/decisions/DR-003-settings-ledger-invariants.md.
157
+ */
158
+ export declare function clear(required: ClearValueRequired, optional?: SettingsValueWriteOptions): Promise<{
140
159
  revisionSeq: number;
141
160
  }>;
142
161
  export interface ResetNamespaceRequired {
@@ -1,5 +1,5 @@
1
1
  import { nowIso as kernelNowIso } from "../primitives/index.js";
2
- import { AliasDepthExceededError, DefinitionInvalidError, DefinitionNotFoundError, DefinitionTombstonedError, ForbiddenError, PrincipalNotFoundError, RenameRetypeConflictError, ScopeNotAllowedError, ValueValidationFailedError, } from "./errors.js";
2
+ import { AliasDepthExceededError, DefinitionInvalidError, DefinitionNotFoundError, DefinitionTombstonedError, ForbiddenError, PrincipalNotFoundError, RenameRetypeConflictError, ScopeNotAllowedError, SettingsRevisionConflictError, ValueValidationFailedError, } from "./errors.js";
3
3
  import { invalidateDefinitionNamespaceCache, resolveDefinitionRaw, validateDefinitionInput, validateValueAgainstSchema, } from "./settings.js";
4
4
  import { SCOPE_BIT } from "./types.js";
5
5
  /**
@@ -148,8 +148,33 @@ async function assertTargetPrincipalInWorkspace(deps, input) {
148
148
  throw new PrincipalNotFoundError(`principal '${input.principalId}' was not found in workspace '${input.workspaceId}'`, input.principalId, input.workspaceId);
149
149
  }
150
150
  }
151
- /** chokepoint write: authorize -> validate -> value + revision, same tx. See docs/decisions/DR-003-settings-ledger-invariants.md. */
152
- export async function set(required) {
151
+ /**
152
+ * Check the addressed value after appendRevision has taken the ledger lock. On Postgres, a read
153
+ * before that lock can see the same old seq in two READ COMMITTED transactions and lose an update.
154
+ * The caller's enclosing transaction rolls the appended revision back on conflict.
155
+ * @complexity At most one scoped value read; no reads when the option is omitted.
156
+ */
157
+ async function assertExpectedRevision(required, optional = {}) {
158
+ if (optional.expectedRevisionSeq === undefined)
159
+ return;
160
+ const { repo, settingId, input } = required;
161
+ const current = input.scope === "global"
162
+ ? await repo.getGlobalValue(settingId)
163
+ : input.scope === "workspace"
164
+ ? await repo.getWorkspaceValue({ workspaceId: input.workspaceId, settingId })
165
+ : await repo.getUserValue({ workspaceId: input.workspaceId, principalId: input.principalId ?? input.callerPrincipalId, settingId });
166
+ const actualRevisionSeq = current?.seq ?? 0;
167
+ if (actualRevisionSeq !== optional.expectedRevisionSeq) {
168
+ throw new SettingsRevisionConflictError({ expectedRevisionSeq: optional.expectedRevisionSeq, actualRevisionSeq });
169
+ }
170
+ }
171
+ /**
172
+ * Authorize -> validate -> value + revision in one transaction. An optional expectedRevisionSeq
173
+ * refuses a stale scoped value and rolls back its revision; omission keeps unconditional writes.
174
+ * @example await set({ deps, input }, { expectedRevisionSeq: snapshotSeq });
175
+ * See docs/decisions/DR-003-settings-ledger-invariants.md.
176
+ */
177
+ export async function set(required, optional = {}) {
153
178
  const { deps, input } = required;
154
179
  const permission = input.requiredPermissionOverride ??
155
180
  deriveRequiredPermission({
@@ -190,6 +215,7 @@ export async function set(required) {
190
215
  changeSetId: null,
191
216
  createdAt: now,
192
217
  });
218
+ await assertExpectedRevision({ repo: deps.repo, settingId: definition.settingId, input }, optional);
193
219
  const base = {
194
220
  settingId: definition.settingId,
195
221
  scope: input.scope,
@@ -222,8 +248,14 @@ export async function set(required) {
222
248
  });
223
249
  return result;
224
250
  }
225
- /** chokepoint write: authorize -> value + revision (state='cleared'), same tx. See docs/decisions/DR-003-settings-ledger-invariants.md. */
226
- export async function clear(required) {
251
+ /**
252
+ * Authorize -> cleared value + revision in one transaction; the optional concurrency guard has
253
+ * the same semantics as `set`. With skipTransaction, the enclosing caller must propagate errors
254
+ * so its transaction rolls back the appended revision on conflict.
255
+ * @example await clear({ deps, input }, { expectedRevisionSeq: snapshotSeq });
256
+ * See docs/decisions/DR-003-settings-ledger-invariants.md.
257
+ */
258
+ export async function clear(required, optional = {}) {
227
259
  const { deps, input } = required;
228
260
  if (!input.skipAuthorize) {
229
261
  const permission = deriveRequiredPermission({
@@ -262,6 +294,7 @@ export async function clear(required) {
262
294
  changeSetId: null,
263
295
  createdAt: now,
264
296
  });
297
+ await assertExpectedRevision({ repo: deps.repo, settingId: definition.settingId, input }, optional);
265
298
  const base = {
266
299
  settingId: definition.settingId,
267
300
  scope: input.scope,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/core",
3
- "version": "0.4.9",
3
+ "version": "0.6.10",
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": {