@lunora/do 1.0.0-alpha.26 → 1.0.0-alpha.27

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/dist/index.d.mts CHANGED
@@ -756,6 +756,15 @@ declare class ReactiveCache {
756
756
  * RLS-filtered list, or `getMyProfile()` with no args) would otherwise memoize
757
757
  * the first caller's result under an identity-independent key and serve it to
758
758
  * everyone. Anonymous/subscription callers pass `null` (their own bucket).
759
+ *
760
+ * The discriminator is an opaque `null | string`, NOT just a userId: the wiring
761
+ * layer (`ShardDO#runCachedQuery`) folds the FULL resolved identity — userId
762
+ * plus the `getIdentity()` claims (active-org / role / tenant) — into a single
763
+ * `stableStringify`'d string before it reaches here. That matters because RLS
764
+ * can key on a claim OTHER than userId: a multi-tenant caller whose userId is
765
+ * stable but whose active-org claim varies request-to-request must NOT share a
766
+ * cache entry across those requests. Encoding the whole identity, not the
767
+ * userId alone, is what keeps those contexts isolated.
759
768
  */
760
769
  declare const reactiveCacheKey: (functionPath: string, args: Record<string, unknown>, identity: null | string) => string;
761
770
  /** The system tables `ctx.db.system` can read. */
@@ -1867,7 +1876,9 @@ interface DatabaseWriterLike {
1867
1876
  * since a global table has no shard boundaries to merge across.
1868
1877
  */
1869
1878
  rankPageRows?: (tableName: string, indexName: string, options?: RankPageOptions) => Promise<ShardRankPageResult>;
1870
- replace: (id: string, document: Record<string, unknown>, expectedTable?: string) => Promise<void>;
1879
+ replace: (id: string, document: Record<string, unknown>, expectedTable?: string, options?: {
1880
+ allowExplicitId?: boolean;
1881
+ }) => Promise<void>;
1871
1882
  /**
1872
1883
  * Un-soft-delete a row: clears the `.softDelete()` marker column (a by-id
1873
1884
  * UPDATE, so it works on a row that list reads currently hide). Throws when
package/dist/index.d.ts CHANGED
@@ -756,6 +756,15 @@ declare class ReactiveCache {
756
756
  * RLS-filtered list, or `getMyProfile()` with no args) would otherwise memoize
757
757
  * the first caller's result under an identity-independent key and serve it to
758
758
  * everyone. Anonymous/subscription callers pass `null` (their own bucket).
759
+ *
760
+ * The discriminator is an opaque `null | string`, NOT just a userId: the wiring
761
+ * layer (`ShardDO#runCachedQuery`) folds the FULL resolved identity — userId
762
+ * plus the `getIdentity()` claims (active-org / role / tenant) — into a single
763
+ * `stableStringify`'d string before it reaches here. That matters because RLS
764
+ * can key on a claim OTHER than userId: a multi-tenant caller whose userId is
765
+ * stable but whose active-org claim varies request-to-request must NOT share a
766
+ * cache entry across those requests. Encoding the whole identity, not the
767
+ * userId alone, is what keeps those contexts isolated.
759
768
  */
760
769
  declare const reactiveCacheKey: (functionPath: string, args: Record<string, unknown>, identity: null | string) => string;
761
770
  /** The system tables `ctx.db.system` can read. */
@@ -1867,7 +1876,9 @@ interface DatabaseWriterLike {
1867
1876
  * since a global table has no shard boundaries to merge across.
1868
1877
  */
1869
1878
  rankPageRows?: (tableName: string, indexName: string, options?: RankPageOptions) => Promise<ShardRankPageResult>;
1870
- replace: (id: string, document: Record<string, unknown>, expectedTable?: string) => Promise<void>;
1879
+ replace: (id: string, document: Record<string, unknown>, expectedTable?: string, options?: {
1880
+ allowExplicitId?: boolean;
1881
+ }) => Promise<void>;
1871
1882
  /**
1872
1883
  * Un-soft-delete a row: clears the `.softDelete()` marker column (a by-id
1873
1884
  * UPDATE, so it works on a row that list reads currently hide). Throws when
package/dist/index.mjs CHANGED
@@ -3,13 +3,13 @@ export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, norma
3
3
  export { aggregateTableName, coerceAggregateNumber, encodeAggregateKey, foldAggregateTally, readAggregateValue } from './packem_shared/aggregateTableName-CxNqY1Sl.mjs';
4
4
  export { CountRlsUnsupportedError, mergeWhere, planAggregateLookup, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy } from './packem_shared/CountRlsUnsupportedError-BGxj0pgS.mjs';
5
5
  export { AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, ensureAuthMetricsTables, readAuthMetrics, recordAuthEvent } from './packem_shared/AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs';
6
- export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-BdDLev9w.mjs';
7
- export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs';
6
+ export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-BigrdT_W.mjs';
7
+ export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-CYwBpyTr.mjs';
8
8
  export { SCAN_DEP, createDependencyTracker, depKey } from './packem_shared/SCAN_DEP-DLJF8dsj.mjs';
9
9
  export { renderSql } from './packem_shared/renderSql-D6eUcn2N.mjs';
10
10
  export { diffExternalSource } from './packem_shared/diffExternalSource-Cx9HUPJj.mjs';
11
- export { materializeExternalRows, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-DNcvoLRT.mjs';
12
- export { isSourceDue, liftSourceId, pullExternalSourceTick } from './packem_shared/isSourceDue-BptUN8CR.mjs';
11
+ export { materializeExternalRows, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-CTqZisSC.mjs';
12
+ export { isSourceDue, liftSourceId, pullExternalSourceTick } from './packem_shared/isSourceDue-CYkt7Ru8.mjs';
13
13
  export { FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_TABLE, ensureFunctionMetricsTables, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetrics, readFunctionMetricsTotals, recordFunctionMetric } from './packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
14
14
  export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, FLAGS_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTIONS-Bxdijn66.mjs';
15
15
  export { LogBuffer } from './packem_shared/LogBuffer-B_Ezju_N.mjs';
@@ -22,19 +22,19 @@ export { ReactiveCache, reactiveCacheKey } from './packem_shared/ReactiveCache-B
22
22
  export { serveRelationFanout } from './packem_shared/serveRelationFanout-C56hKu1O.mjs';
23
23
  export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/DEFAULT_MAX_RELATION_KEYS-BEan1CRD.mjs';
24
24
  export { applyOnDelete, fanOutScalarCounts, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-BXSq3S70.mjs';
25
- export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-G1eNK4DQ.mjs';
25
+ export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-DTvHvRzY.mjs';
26
26
  export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/buildFtsMatch-BLEMawrp.mjs';
27
27
  export { M as MIN_ADMIN_TOKEN_LENGTH, a as MIN_AUTH_SECRET_LENGTH, b as buildSecurityAudit } from './packem_shared/security-audit-CucgBice.mjs';
28
- export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-D71QAL5h.mjs';
29
- export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-CpURtawE.mjs';
28
+ export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-BnSKgVO4.mjs';
29
+ export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-wTF0-qXJ.mjs';
30
30
  export { SHARD_REGISTRY_DO_NAME, ShardRegistryDO } from './packem_shared/SHARD_REGISTRY_DO_NAME-D99roc-r.mjs';
31
31
  export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/MAX_SQL_ROWS-D57CJaT9.mjs';
32
32
  export { createSystemReader } from './packem_shared/createSystemReader-D12eNH13.mjs';
33
33
  export { ConflictError } from './packem_shared/ConflictError-CLoq37xH.mjs';
34
34
  export { hasTrigger, runTriggers } from './packem_shared/hasTrigger-5N6_Fx0A.mjs';
35
35
  export { compileWhereSql } from './packem_shared/compileWhereSql-DE6yfRcQ.mjs';
36
- export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-DZSVKRr7.mjs';
36
+ export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-DjJEHiM2.mjs';
37
37
  export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-DDoT-UUI.mjs';
38
- export { runShardMigrations } from './packem_shared/runShardMigrations-DeZr0KZp.mjs';
38
+ export { runShardMigrations } from './packem_shared/runShardMigrations-BGx4v2B6.mjs';
39
39
  export { stableStringify } from './packem_shared/stableStringify-MydiuScU.mjs';
40
40
  export { s as subscriptionListDeltas } from './packem_shared/subscription-delivery-CK8qga-k.mjs';
@@ -95,7 +95,7 @@ const applyCdcChange = async (writer, change) => {
95
95
  fields[key] = value;
96
96
  }
97
97
  }
98
- await writer.replace(change.id, fields);
98
+ await writer.replace(change.id, fields, void 0, { allowExplicitId: true });
99
99
  }
100
100
  };
101
101
  const applyCdcChanges = async (writer, changes) => {
@@ -178,7 +178,9 @@ const runDataMigration = async (options) => {
178
178
  if (next !== void 0) {
179
179
  changed += 1;
180
180
  if (!dryRun) {
181
- await writer.replace(String(document["_id"]), { ...next, _creationTime: document["_creationTime"], _id: document["_id"] });
181
+ await writer.replace(String(document["_id"]), { ...next, _creationTime: document["_creationTime"], _id: document["_id"] }, void 0, {
182
+ allowExplicitId: true
183
+ });
182
184
  }
183
185
  }
184
186
  if (!dryRun) {
@@ -3,8 +3,8 @@ import { sql } from 'drizzle-orm';
3
3
  import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs';
4
4
  import { encodeAggregateKey, foldAggregateTally, aggregateTableName, coerceAggregateNumber, readAggregateValue } from './aggregateTableName-CxNqY1Sl.mjs';
5
5
  import { mergeWhere, CountRlsUnsupportedError, selectIndexForGroupBy, selectIndexForCount, selectIndexForAggregate } from './CountRlsUnsupportedError-BGxj0pgS.mjs';
6
- import { appendCdcChange } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
7
- export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
6
+ import { appendCdcChange } from './CDC_LOG_TABLE-DjJEHiM2.mjs';
7
+ export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-DjJEHiM2.mjs';
8
8
  import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
9
9
  import { i as isFtsAvailable, D as DOC_COLUMN$1, r as rowToDocument, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT, d as aggUpsertSql, j as jsonPathSql, q as quoteIdentifier, t as tableColumns, e as qualifiedJsonPathSql } from './do-sql-BCHCWtrD.mjs';
10
10
  import { param } from './renderSql-D6eUcn2N.mjs';
@@ -16,14 +16,14 @@ import { decodeCursor, normalizeOrderKeys, buildSeekWhere, applySelect, encodeCu
16
16
  import NotFoundError from './NotFoundError-C70b9hLw.mjs';
17
17
  import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-BEan1CRD.mjs';
18
18
  import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-BXSq3S70.mjs';
19
- import { guardWriter } from './RLS_UNWRAP_SYMBOL-G1eNK4DQ.mjs';
19
+ import { guardWriter } from './RLS_UNWRAP_SYMBOL-DTvHvRzY.mjs';
20
20
  import { createSystemReader } from './createSystemReader-D12eNH13.mjs';
21
21
  import { ConflictError } from './ConflictError-CLoq37xH.mjs';
22
22
  import { runTriggers } from './hasTrigger-5N6_Fx0A.mjs';
23
23
  import { compileWhereSql } from './compileWhereSql-DE6yfRcQ.mjs';
24
24
  export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-DDoT-UUI.mjs';
25
25
  export { C as CLIENT_WATERMARK_TABLE, G as GLOBAL_SHAPE_SNAPSHOT_TABLE, I as IDEMPOTENCY_TABLE, c as advanceClientWatermark, d as deleteGlobalShapeSnapshot, e as deleteGlobalShapeSnapshotsForConnection, m as migrateClientWatermark, b as migrateGlobalShapeSnapshot, r as readClientWatermark, f as readGlobalShapeSnapshot, g as readIdempotent, t as trimIdempotent, w as writeGlobalShapeSnapshot, h as writeIdempotent } from './ctx-db-idempotency-BdcNpvY4.mjs';
26
- export { runShardMigrations } from './runShardMigrations-DeZr0KZp.mjs';
26
+ export { runShardMigrations } from './runShardMigrations-BGx4v2B6.mjs';
27
27
  export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
28
28
 
29
29
  const rankIndexFieldsUnchanged = (index, previous, next) => {
@@ -1574,7 +1574,7 @@ const createShardCtxDb = (options) => {
1574
1574
  } else {
1575
1575
  id = generateId();
1576
1576
  }
1577
- const creationTime = typeof withDefaults["_creationTime"] === "number" ? withDefaults["_creationTime"] : clock();
1577
+ const creationTime = insertOptions?.allowExplicitId && typeof withDefaults["_creationTime"] === "number" ? withDefaults["_creationTime"] : clock();
1578
1578
  const documentWithMeta = { ...withDefaults, _creationTime: creationTime, _id: id };
1579
1579
  if (hasMatchingTrigger(tableName, "before", "insert")) {
1580
1580
  await fireTriggers("before", "insert", { doc: { ...documentWithMeta }, id, op: "insert", table: tableName });
@@ -1617,7 +1617,7 @@ const createShardCtxDb = (options) => {
1617
1617
  const rows = documents.map((document) => {
1618
1618
  const withDefaults = applyInsertDefaults(definition, document, auth);
1619
1619
  const id = batchOptions?.allowExplicitId === true && typeof withDefaults["_id"] === "string" ? withDefaults["_id"] : generateId();
1620
- const creationTime = typeof withDefaults["_creationTime"] === "number" ? withDefaults["_creationTime"] : clock();
1620
+ const creationTime = batchOptions?.allowExplicitId === true && typeof withDefaults["_creationTime"] === "number" ? withDefaults["_creationTime"] : clock();
1621
1621
  return { creationTime, document: { ...withDefaults, _creationTime: creationTime, _id: id }, id };
1622
1622
  });
1623
1623
  const valuesSql = sql.join(
@@ -1847,12 +1847,12 @@ const createShardCtxDb = (options) => {
1847
1847
  syncRanks(located.tableName, id, void 0, located.row);
1848
1848
  }
1849
1849
  },
1850
- async replace(id, document, expectedTable) {
1850
+ async replace(id, document, expectedTable, replaceOptions) {
1851
1851
  const located = locateRowById(id, expectedTable);
1852
1852
  if (!located) {
1853
1853
  const global = expectedTable === void 0 ? globalFallback() : void 0;
1854
1854
  if (global) {
1855
- await global.replace(id, document);
1855
+ await global.replace(id, document, void 0, replaceOptions);
1856
1856
  return;
1857
1857
  }
1858
1858
  throw new LunoraError("INTERNAL", `document not found: ${id}`);
@@ -1863,7 +1863,7 @@ const createShardCtxDb = (options) => {
1863
1863
  throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
1864
1864
  }
1865
1865
  assertNoExplicitUndefined("replace", document);
1866
- const creationTime = typeof document["_creationTime"] === "number" ? document["_creationTime"] : clock();
1866
+ const creationTime = replaceOptions?.allowExplicitId && typeof document["_creationTime"] === "number" ? document["_creationTime"] : clock();
1867
1867
  const replaced = { ...document, _creationTime: creationTime, _id: id };
1868
1868
  applyOnUpdate(tableDefinition, document, replaced, auth);
1869
1869
  runRowValidators(tableDefinition, replaced);
@@ -120,9 +120,9 @@ const guardWriter = (raw, schema, tableOfId) => {
120
120
  guardTable(tableName);
121
121
  return base.rankPage(tableName, indexName, options);
122
122
  },
123
- replace: async (id, document, expectedTable) => {
123
+ replace: async (id, document, expectedTable, options) => {
124
124
  await guardById(id, expectedTable);
125
- return base.replace(id, document, expectedTable);
125
+ return base.replace(id, document, expectedTable, options);
126
126
  },
127
127
  restore: async (id, expectedTable) => {
128
128
  await guardById(id, expectedTable);
@@ -1,10 +1,11 @@
1
1
  import { LunoraError, toErrorBody } from '@lunora/errors';
2
2
  import { drizzle } from 'drizzle-orm/durable-sqlite';
3
+ import { c as constantTimeEqual } from './constant-time-equal-BVRWZgES.mjs';
3
4
  import { j as jsonResponse } from './json-response-BdbtpOhm.mjs';
4
5
  import { e as encodeWire, a as awaitWsDrain, t as trySendFrame, d as decodeWire, s as subscriptionListDeltas, b as sendDeltaFrames } from './subscription-delivery-CK8qga-k.mjs';
5
6
  import { parseExportShardArgs, parseImportShardArgs } from './exportShardRows-Dy3oFZ26.mjs';
6
7
  import { recordAuthEvent, readAuthMetrics } from './AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs';
7
- import { DATA_MIGRATION_STATE_TABLE, readMigrationStatus } from './DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs';
8
+ import { DATA_MIGRATION_STATE_TABLE, readMigrationStatus } from './DATA_MIGRATION_STATE_TABLE-CYwBpyTr.mjs';
8
9
  import { SCAN_DEP, createDependencyTracker, tableFromDepKey } from './SCAN_DEP-DLJF8dsj.mjs';
9
10
  import { readFunctionMetricsTotals, readFunctionMetricIndexHits, recordFunctionMetric, mergeScanAttribution, readFunctionMetrics, readFunctionMetricBuckets } from './FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
10
11
  import { createFanoutCounters, ADMIN_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, selectMatchingIds, ADMIN_FUNCTIONS, findStorageReferences, listTables, summarizeSubscriptions, summarizeFanoutTopics, readTablePage, facetColumn, FLAGS_FUNCTION_PREFIX, recordFanoutPass, MAX_PAGE_SIZE } from './ADMIN_FUNCTIONS-Bxdijn66.mjs';
@@ -18,7 +19,7 @@ import { i as isDevEnvironment, c as buildSettings, b as buildSecurityAudit } fr
18
19
  import { runReadonlySql } from './MAX_SQL_ROWS-D57CJaT9.mjs';
19
20
  import { ConflictError } from './ConflictError-CLoq37xH.mjs';
20
21
  import { e as deleteGlobalShapeSnapshotsForConnection, g as readIdempotent, h as writeIdempotent, t as trimIdempotent, r as readClientWatermark, m as migrateClientWatermark, c as advanceClientWatermark, d as deleteGlobalShapeSnapshot, f as readGlobalShapeSnapshot, w as writeGlobalShapeSnapshot } from './ctx-db-idempotency-BdcNpvY4.mjs';
21
- import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
22
+ import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-DjJEHiM2.mjs';
22
23
  import { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
23
24
 
24
25
  const MAX_BATCH_ENTRIES = 500;
@@ -399,18 +400,6 @@ const relaySecretOf = (env) => {
399
400
  const value = env?.[RELAY_SECRET_KEY];
400
401
  return typeof value === "string" && value.length > 0 ? value : void 0;
401
402
  };
402
- const constantTimeEqual$1 = (a, b) => {
403
- if (a.length !== b.length) {
404
- return false;
405
- }
406
- let mismatch = 0;
407
- for (let index = 0; index < a.length; index += 1) {
408
- const charA = a.charCodeAt(index);
409
- const charB = b.charCodeAt(index);
410
- mismatch |= charA ^ charB;
411
- }
412
- return mismatch === 0;
413
- };
414
403
  const signRelayBody = async (secret, body) => {
415
404
  const encoder = new TextEncoder();
416
405
  const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
@@ -463,7 +452,7 @@ class RelayLink {
463
452
  if (secret !== void 0) {
464
453
  const supplied = request.headers.get(RELAY_SIGNATURE_HEADER);
465
454
  const expected = await signRelayBody(secret, raw);
466
- if (supplied === null || !constantTimeEqual$1(supplied, expected)) {
455
+ if (supplied === null || !constantTimeEqual(supplied, expected)) {
467
456
  return new Response("forbidden", { status: 403 });
468
457
  }
469
458
  }
@@ -1894,16 +1883,6 @@ const extractBearerToken = (authorization) => {
1894
1883
  const value = rest.join(" ").trim();
1895
1884
  return value.length > 0 ? value : void 0;
1896
1885
  };
1897
- const constantTimeEqual = (a, b) => {
1898
- const max = Math.max(a.length, b.length);
1899
- let diff = a.length ^ b.length;
1900
- for (let index = 0; index < max; index += 1) {
1901
- const charA = index < a.length ? a.charCodeAt(index) : 0;
1902
- const charB = index < b.length ? b.charCodeAt(index) : 0;
1903
- diff |= charA ^ charB;
1904
- }
1905
- return diff === 0;
1906
- };
1907
1886
  class ShardDO {
1908
1887
  /**
1909
1888
  * Per-socket cap on concurrent stream iterators. Each in-flight stream
@@ -3809,8 +3788,17 @@ class ShardDO {
3809
3788
  const tracker = createDependencyTracker();
3810
3789
  this.currentTracker = tracker;
3811
3790
  const hitsBefore = this.reactiveCache.stats().hits;
3791
+ const userId = this.getCurrentUserId();
3792
+ const claims = this.getCurrentIdentity();
3793
+ const identity = userId === void 0 && claims === void 0 ? (
3794
+ // eslint-disable-next-line unicorn/no-null -- reactiveCacheKey's identity arg is `null | string`; null is the documented "anonymous caller" discriminator
3795
+ null
3796
+ ) : (
3797
+ // eslint-disable-next-line unicorn/no-null -- fold userId/claims into the discriminator; missing fields serialize as null so the shape stays canonical
3798
+ stableStringify({ claims: claims ?? null, userId: userId ?? null })
3799
+ );
3812
3800
  try {
3813
- const result = await this.reactiveCache.run(reactiveCacheKey(functionPath, args, this.getCurrentUserId() ?? null), tracker.collect(), run);
3801
+ const result = await this.reactiveCache.run(reactiveCacheKey(functionPath, args, identity), tracker.collect(), run);
3814
3802
  this.currentRequestCacheHit = this.reactiveCache.stats().hits > hitsBefore;
3815
3803
  this.currentRequestReadTables = tablesFromDeps(tracker.collect());
3816
3804
  return result;
@@ -1,3 +1,4 @@
1
+ import { c as constantTimeEqual } from './constant-time-equal-BVRWZgES.mjs';
1
2
  import { j as jsonResponse } from './json-response-BdbtpOhm.mjs';
2
3
 
3
4
  const SESSION_DO_TTL_DEFAULT = 7 * 24 * 60 * 60;
@@ -9,16 +10,6 @@ const SESSION_TOKEN_PATTERN = /^[\w-]+$/;
9
10
  const MIN_TOKEN_LENGTH = 32;
10
11
  const MAX_TOKEN_LENGTH = 256;
11
12
  const MAX_USER_ID_LENGTH = 256;
12
- const constantTimeEqual = (a, b) => {
13
- const max = Math.max(a.length, b.length);
14
- let diff = a.length ^ b.length;
15
- for (let index = 0; index < max; index += 1) {
16
- const charA = index < a.length ? a.charCodeAt(index) : 0;
17
- const charB = index < b.length ? b.charCodeAt(index) : 0;
18
- diff |= charA ^ charB;
19
- }
20
- return diff === 0;
21
- };
22
13
  const isAuthorized = (request, env) => {
23
14
  const expected = env.SESSION_DO_SECRET;
24
15
  if (typeof expected !== "string" || expected.length === 0) {
@@ -0,0 +1,12 @@
1
+ const constantTimeEqual = (a, b) => {
2
+ const max = Math.max(a.length, b.length);
3
+ let diff = a.length ^ b.length;
4
+ for (let index = 0; index < max; index += 1) {
5
+ const charA = index < a.length ? a.charCodeAt(index) : 0;
6
+ const charB = index < b.length ? b.charCodeAt(index) : 0;
7
+ diff |= charA ^ charB;
8
+ }
9
+ return diff === 0;
10
+ };
11
+
12
+ export { constantTimeEqual as c };
@@ -1,5 +1,5 @@
1
1
  import { LunoraError } from '@lunora/errors';
2
- import { runExternalSourceTick } from './materializeExternalRows-DNcvoLRT.mjs';
2
+ import { runExternalSourceTick } from './materializeExternalRows-CTqZisSC.mjs';
3
3
 
4
4
  const liftSourceId = (row, options = {}) => {
5
5
  const { idColumn = "id", map } = options;
@@ -1,4 +1,4 @@
1
- import { applyCdcChanges } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
1
+ import { applyCdcChanges } from './CDC_LOG_TABLE-DjJEHiM2.mjs';
2
2
  import { s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
3
3
  import { diffExternalSource, projectExternalSourceRow } from './diffExternalSource-Cx9HUPJj.mjs';
4
4
  import { stableStringify } from './stableStringify-MydiuScU.mjs';
@@ -1,6 +1,6 @@
1
1
  import { sql } from 'drizzle-orm';
2
2
  import { aggregateTableName } from './aggregateTableName-CxNqY1Sl.mjs';
3
- import { migrateCdcLog, migrateCdcMeta } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
3
+ import { migrateCdcLog, migrateCdcMeta } from './CDC_LOG_TABLE-DjJEHiM2.mjs';
4
4
  import { m as migrateClientWatermark, a as migrateIdempotency, b as migrateGlobalShapeSnapshot } from './ctx-db-idempotency-BdcNpvY4.mjs';
5
5
  import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
6
6
  import { D as DOC_COLUMN, j as jsonPathSql, c as createIndexSql, t as tableColumns, i as isFtsAvailable, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT } from './do-sql-BCHCWtrD.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/do",
3
- "version": "1.0.0-alpha.26",
3
+ "version": "1.0.0-alpha.27",
4
4
  "description": "Lunora Durable Objects: ShardDO (SQLite, OCC, hibernated WebSocket subscriptions) and SessionDO",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -46,7 +46,7 @@
46
46
  "access": "public"
47
47
  },
48
48
  "dependencies": {
49
- "@lunora/errors": "1.0.0-alpha.3",
49
+ "@lunora/errors": "1.0.0-alpha.4",
50
50
  "@visulima/redact": "3.0.0",
51
51
  "drizzle-orm": "^0.45.2"
52
52
  },