@agentshouse/mdruntime 0.1.0-alpha.7 → 0.1.0-alpha.8

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.
Files changed (54) hide show
  1. package/dist/adapter.d.ts +40 -4
  2. package/dist/adapter.d.ts.map +1 -1
  3. package/dist/adapter.js.map +1 -1
  4. package/dist/bootstrap.d.ts +3 -1
  5. package/dist/bootstrap.d.ts.map +1 -1
  6. package/dist/bootstrap.js +12 -6
  7. package/dist/bootstrap.js.map +1 -1
  8. package/dist/change.d.ts +1 -0
  9. package/dist/change.d.ts.map +1 -1
  10. package/dist/change.js.map +1 -1
  11. package/dist/collection.d.ts +8 -3
  12. package/dist/collection.d.ts.map +1 -1
  13. package/dist/collection.js +66 -28
  14. package/dist/collection.js.map +1 -1
  15. package/dist/connection.d.ts +10 -3
  16. package/dist/connection.d.ts.map +1 -1
  17. package/dist/connection.js +330 -21
  18. package/dist/connection.js.map +1 -1
  19. package/dist/identity.d.ts +2 -0
  20. package/dist/identity.d.ts.map +1 -0
  21. package/dist/identity.js +16 -0
  22. package/dist/identity.js.map +1 -0
  23. package/dist/index.d.ts +4 -1
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/memory.d.ts +2 -0
  27. package/dist/memory.d.ts.map +1 -1
  28. package/dist/memory.js +27 -6
  29. package/dist/memory.js.map +1 -1
  30. package/dist/model.d.ts +70 -0
  31. package/dist/model.d.ts.map +1 -0
  32. package/dist/model.js +28 -0
  33. package/dist/model.js.map +1 -0
  34. package/dist/query.d.ts +12 -0
  35. package/dist/query.d.ts.map +1 -0
  36. package/dist/query.js +18 -0
  37. package/dist/query.js.map +1 -0
  38. package/dist/refresh.d.ts +2 -1
  39. package/dist/refresh.d.ts.map +1 -1
  40. package/dist/refresh.js +6 -4
  41. package/dist/refresh.js.map +1 -1
  42. package/dist/replica.d.ts +3 -1
  43. package/dist/replica.d.ts.map +1 -1
  44. package/dist/replica.js +10 -6
  45. package/dist/replica.js.map +1 -1
  46. package/dist/save.d.ts +6 -1
  47. package/dist/save.d.ts.map +1 -1
  48. package/dist/save.js +31 -9
  49. package/dist/save.js.map +1 -1
  50. package/dist/store.d.ts +7 -2
  51. package/dist/store.d.ts.map +1 -1
  52. package/dist/store.js +1 -1
  53. package/dist/store.js.map +1 -1
  54. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdruntime/src/memory.ts"],"sourcesContent":["import {\n ROOM_CONTRACT_VERSION,\n type ActionRequest,\n type ActionResult,\n type Adapter,\n type Authorization,\n type BootstrapRequest,\n type BootstrapResult,\n type Capability,\n type DiscoverResult,\n type DiscoveredRoom,\n type HistoryRequest,\n type HistoryResult,\n type MdModelIdentity,\n type MutationRequest,\n type MutationResult,\n type ProviderLimit,\n type RefreshRequest,\n type RefreshResult,\n type Retention,\n} from './adapter.js';\nimport { MD_MODEL } from './collection.js';\n\nexport type MemoryRoom = DiscoveredRoom & {\n documents?: Readonly<Record<string, string>>;\n revisions?: Readonly<Record<string, string>>;\n binaryTargets?: readonly string[];\n};\n\nexport type MemoryAdapterOptions = {\n rooms?: readonly MemoryRoom[];\n pageSize?: number;\n mdModel?: MdModelIdentity;\n supportedVersions?: readonly number[];\n capabilities?: readonly Capability[];\n providerLimits?: readonly ProviderLimit[];\n retention?: Retention;\n origins?: readonly string[];\n};\n\nexport type MemoryAdapter = Adapter & {\n setRooms(rooms: readonly MemoryRoom[]): void;\n script(operation: keyof Adapter, answer: unknown): void;\n};\n\ntype Script<T, R> = T | ((request: R) => T | Promise<T>);\n\ntype RefreshContinuation = {\n room: MemoryRoom;\n from: MemoryRoom;\n at: number;\n};\n\nfunction named(\n source: Readonly<Record<string, string>>,\n paths: readonly string[],\n): Readonly<Record<string, string>> {\n const taken: Record<string, string> = {};\n for (const path of paths) {\n const value = source[path];\n if (value !== undefined) taken[path] = value;\n }\n return taken;\n}\n\nasync function resolveScript<T, R>(\n answer: Script<T, R> | undefined,\n fallback: () => T | Promise<T>,\n request: R,\n) {\n if (answer === undefined) return fallback();\n return typeof answer === 'function' ? (answer as (value: R) => T | Promise<T>)(request) : answer;\n}\n\nexport function createMemoryAdapter(options: MemoryAdapterOptions = {}): MemoryAdapter {\n let rooms = options.rooms === undefined ? [] : [...options.rooms];\n const mdModel = options.mdModel ?? MD_MODEL;\n const supportedVersions = options.supportedVersions ?? [ROOM_CONTRACT_VERSION];\n const capabilities = options.capabilities ?? [];\n const providerLimits = options.providerLimits ?? [];\n const retention = options.retention ?? { history: 1, outcome: 1, refreshHorizon: 1 };\n const origins = options.origins ?? ['https://origin.example'];\n const pageSize = options.pageSize;\n const scripts: Partial<Record<keyof Adapter, unknown>> = {};\n const served = new Map<string, Map<string, MemoryRoom>>();\n const refreshPages = new Map<string, RefreshContinuation>();\n\n function retain(entries: readonly MemoryRoom[]) {\n for (const room of entries) {\n const versions = served.get(room.locator) ?? new Map<string, MemoryRoom>();\n versions.set(room.roomVersion, room);\n served.set(room.locator, versions);\n }\n }\n\n retain(rooms);\n\n function declared(room: MemoryRoom): DiscoveredRoom {\n return {\n name: room.name,\n locator: room.locator,\n roomVersion: room.roomVersion,\n writeGrants: room.writeGrants,\n providerOwnedPaths: room.providerOwnedPaths,\n };\n }\n\n function page(room: MemoryRoom, from: number): BootstrapResult {\n const paths = Object.keys(room.documents ?? {}).sort();\n const size = pageSize ?? paths.length;\n const taken = paths.slice(from, from + size);\n const next = from + taken.length;\n return {\n kind: 'bootstrap',\n roomVersion: room.roomVersion,\n documents: named(room.documents ?? {}, taken),\n revisions: named(room.revisions ?? {}, taken),\n binaryTargets: from === 0 ? (room.binaryTargets ?? []) : [],\n ...(next < paths.length ? { pageToken: String(next) } : {}),\n };\n }\n\n function advancement(room: MemoryRoom, from: MemoryRoom, at: number): RefreshResult {\n const current = room.documents ?? {};\n const previous = from.documents ?? {};\n const currentTargets = new Set(room.binaryTargets ?? []);\n const previousTargets = new Set(from.binaryTargets ?? []);\n const changed = Object.keys(current)\n .filter((path) => current[path] !== previous[path])\n .sort();\n const size = pageSize ?? changed.length;\n const taken = changed.slice(at, at + size);\n const next = at + taken.length;\n const opening = at === 0;\n const pageToken = next < changed.length ? `refresh-${refreshPages.size}` : undefined;\n if (pageToken !== undefined) refreshPages.set(pageToken, { room, from, at: next });\n return {\n kind: 'net-advancement',\n roomVersion: room.roomVersion,\n documents: named(current, taken),\n revisions: named(room.revisions ?? {}, taken),\n binaryTargets: opening\n ? [...currentTargets].filter((target) => !previousTargets.has(target))\n : [],\n removals: opening\n ? [\n ...Object.keys(previous).filter(\n (path) => !(path in current) && !currentTargets.has(path),\n ),\n ...[...previousTargets].filter(\n (target) => !currentTargets.has(target) && !(target in current),\n ),\n ].sort()\n : [],\n ...(pageToken === undefined ? {} : { pageToken }),\n };\n }\n\n function discovery(): DiscoverResult {\n return {\n kind: 'discovery',\n supportedVersions,\n mdModel,\n rooms: rooms.map(declared),\n capabilities,\n providerLimits,\n retention,\n origins,\n };\n }\n\n return {\n setRooms(next) {\n rooms = [...next];\n retain(rooms);\n },\n script(operation, answer) {\n if (answer === undefined) delete scripts[operation];\n else scripts[operation] = answer;\n },\n async authorize() {\n return resolveScript<Authorization, void>(\n scripts.authorize as Script<Authorization, void> | undefined,\n () => ({}),\n undefined,\n );\n },\n async discover(_authorization: Authorization) {\n return resolveScript<DiscoverResult, void>(\n scripts.discover as Script<DiscoverResult, void> | undefined,\n discovery,\n undefined,\n );\n },\n async bootstrap(_authorization: Authorization, request: BootstrapRequest) {\n return resolveScript<BootstrapResult, BootstrapRequest>(\n scripts.bootstrap as Script<BootstrapResult, BootstrapRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));\n },\n request,\n );\n },\n async refresh(_authorization: Authorization, request: RefreshRequest) {\n return resolveScript<RefreshResult, RefreshRequest>(\n scripts.refresh as Script<RefreshResult, RefreshRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n if (request.pageToken !== undefined) {\n const continuation = refreshPages.get(request.pageToken);\n if (\n continuation === undefined ||\n continuation.room.locator !== request.locator ||\n continuation.from.roomVersion !== request.fromRoomVersion\n ) {\n throw new Error('Invalid Refresh Page Token');\n }\n return advancement(continuation.room, continuation.from, continuation.at);\n }\n if (request.fromRoomVersion === room.roomVersion) {\n return { kind: 'still-current' };\n }\n const from = served.get(room.locator)?.get(request.fromRoomVersion);\n if (from === undefined) return { kind: 'beyond-horizon' };\n return advancement(room, from, 0);\n },\n request,\n );\n },\n async mutate(_authorization: Authorization, request: MutationRequest) {\n return resolveScript<MutationResult, MutationRequest>(\n scripts.mutate as Script<MutationResult, MutationRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n return { kind: 'rejected', text: '', affected: {} };\n },\n request,\n );\n },\n async history(_authorization: Authorization, request: HistoryRequest) {\n return resolveScript<HistoryResult, HistoryRequest>(\n scripts.history as Script<HistoryResult, HistoryRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n return {\n kind: 'history',\n revisions: [],\n };\n },\n request,\n );\n },\n async action(_authorization: Authorization, request: ActionRequest) {\n return resolveScript<ActionResult, ActionRequest>(\n scripts.action as Script<ActionResult, ActionRequest> | undefined,\n () => ({\n kind: 'rejected',\n text: '',\n }),\n request,\n );\n },\n };\n}\n"],"names":["ROOM_CONTRACT_VERSION","MD_MODEL","named","source","paths","taken","path","value","undefined","resolveScript","answer","fallback","request","createMemoryAdapter","options","rooms","mdModel","supportedVersions","capabilities","providerLimits","retention","history","outcome","refreshHorizon","origins","pageSize","scripts","served","Map","refreshPages","retain","entries","room","versions","get","locator","set","roomVersion","declared","name","writeGrants","providerOwnedPaths","page","from","Object","keys","documents","sort","size","length","slice","next","kind","revisions","binaryTargets","pageToken","String","advancement","at","current","previous","currentTargets","Set","previousTargets","changed","filter","opening","target","has","removals","discovery","map","setRooms","script","operation","authorize","discover","_authorization","bootstrap","find","entry","Number","refresh","continuation","fromRoomVersion","Error","mutate","text","affected","action"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/memory.ts"],"sourcesContent":["import type { ModelResult } from './model.js';\nimport {\n ROOM_CONTRACT_VERSION,\n type ActionRequest,\n type ActionResult,\n type Adapter,\n type Authorization,\n type BootstrapRequest,\n type BootstrapResult,\n type Capability,\n type DiscoverResult,\n type DiscoveredRoom,\n type HistoryRequest,\n type HistoryResult,\n type MdModelIdentity,\n type MutationRequest,\n type MutationResult,\n type ProviderLimit,\n type RefreshRequest,\n type RefreshResult,\n type Retention,\n} from './adapter.js';\nimport { MD_MODEL } from './collection.js';\n\nconst FIXTURE_RETENTION: Retention = {\n history: { kind: 'duration', seconds: 1 },\n outcome: 1,\n refreshHorizon: 1,\n};\n\nfunction declaredRetention(value: Retention | undefined): Retention {\n const retention = value ?? FIXTURE_RETENTION;\n if (retention.history.kind === 'no-declared-time-bound') return retention;\n if (Number.isFinite(retention.history.seconds) && retention.history.seconds > 0) {\n return retention;\n }\n throw new Error('history retention duration must be a finite positive number of seconds');\n}\n\nexport type MemoryRoom = DiscoveredRoom & {\n model?: ModelResult;\n documents?: Readonly<Record<string, string>>;\n revisions?: Readonly<Record<string, string>>;\n binaryTargets?: readonly string[];\n};\n\nexport type MemoryAdapterOptions = {\n rooms?: readonly MemoryRoom[];\n pageSize?: number;\n mdModel?: MdModelIdentity;\n supportedVersions?: readonly number[];\n capabilities?: readonly Capability[];\n providerLimits?: readonly ProviderLimit[];\n retention?: Retention;\n origins?: readonly string[];\n};\n\nexport type MemoryAdapter = Adapter & {\n setRooms(rooms: readonly MemoryRoom[]): void;\n script(operation: keyof Adapter, answer: unknown): void;\n};\n\ntype Script<T, R> = T | ((request: R) => T | Promise<T>);\n\ntype RefreshContinuation = {\n room: MemoryRoom;\n from: MemoryRoom;\n at: number;\n};\n\nfunction named(\n source: Readonly<Record<string, string>>,\n paths: readonly string[],\n): Readonly<Record<string, string>> {\n const taken: Record<string, string> = {};\n for (const path of paths) {\n const value = source[path];\n if (value !== undefined) taken[path] = value;\n }\n return taken;\n}\n\nasync function resolveScript<T, R>(\n answer: Script<T, R> | undefined,\n fallback: () => T | Promise<T>,\n request: R,\n) {\n if (answer === undefined) return fallback();\n return typeof answer === 'function' ? (answer as (value: R) => T | Promise<T>)(request) : answer;\n}\n\nexport function createMemoryAdapter(options: MemoryAdapterOptions = {}): MemoryAdapter {\n let rooms = options.rooms === undefined ? [] : [...options.rooms];\n const mdModel = options.mdModel ?? MD_MODEL;\n const supportedVersions = options.supportedVersions ?? [ROOM_CONTRACT_VERSION];\n const capabilities = options.capabilities ?? [];\n const providerLimits = options.providerLimits ?? [];\n const retention = declaredRetention(options.retention);\n const origins = options.origins ?? ['https://origin.example'];\n const pageSize = options.pageSize;\n const scripts: Partial<Record<keyof Adapter, unknown>> = {};\n const served = new Map<string, Map<string, MemoryRoom>>();\n const refreshPages = new Map<string, RefreshContinuation>();\n\n function retain(entries: readonly MemoryRoom[]) {\n for (const room of entries) {\n const versions = served.get(room.locator) ?? new Map<string, MemoryRoom>();\n versions.set(room.roomVersion, room);\n served.set(room.locator, versions);\n }\n }\n\n retain(rooms);\n\n function declared(room: MemoryRoom): DiscoveredRoom {\n return {\n name: room.name,\n locator: room.locator,\n collectionRoot: room.collectionRoot,\n roomVersion: room.roomVersion,\n operations: room.operations,\n replica: room.replica,\n attachedModel: room.attachedModel,\n providerOwnedPaths: room.providerOwnedPaths,\n };\n }\n\n function page(room: MemoryRoom, from: number): BootstrapResult {\n const paths = Object.keys(room.documents ?? {}).sort();\n const size = pageSize ?? paths.length;\n const taken = paths.slice(from, from + size);\n const next = from + taken.length;\n return {\n kind: 'bootstrap',\n roomVersion: room.roomVersion,\n documents: named(room.documents ?? {}, taken),\n revisions: named(room.revisions ?? {}, taken),\n binaryTargets: from === 0 ? (room.binaryTargets ?? []) : [],\n ...(next < paths.length ? { pageToken: String(next) } : {}),\n };\n }\n\n function advancement(room: MemoryRoom, from: MemoryRoom, at: number): RefreshResult {\n const current = room.documents ?? {};\n const previous = from.documents ?? {};\n const currentTargets = new Set(room.binaryTargets ?? []);\n const previousTargets = new Set(from.binaryTargets ?? []);\n const changed = Object.keys(current)\n .filter((path) => current[path] !== previous[path])\n .sort();\n const size = pageSize ?? changed.length;\n const taken = changed.slice(at, at + size);\n const next = at + taken.length;\n const opening = at === 0;\n const pageToken = next < changed.length ? `refresh-${refreshPages.size}` : undefined;\n if (pageToken !== undefined) refreshPages.set(pageToken, { room, from, at: next });\n return {\n kind: 'net-advancement',\n roomVersion: room.roomVersion,\n documents: named(current, taken),\n revisions: named(room.revisions ?? {}, taken),\n binaryTargets: opening\n ? [...currentTargets].filter((target) => !previousTargets.has(target))\n : [],\n removals: opening\n ? [\n ...Object.keys(previous).filter(\n (path) => !(path in current) && !currentTargets.has(path),\n ),\n ...[...previousTargets].filter(\n (target) => !currentTargets.has(target) && !(target in current),\n ),\n ].sort()\n : [],\n ...(pageToken === undefined ? {} : { pageToken }),\n };\n }\n\n function discovery(): DiscoverResult {\n return {\n kind: 'discovery',\n supportedVersions,\n mdModel,\n rooms: rooms.map(declared),\n capabilities,\n providerLimits,\n retention,\n origins,\n };\n }\n\n return {\n setRooms(next) {\n rooms = [...next];\n retain(rooms);\n },\n script(operation, answer) {\n if (answer === undefined) delete scripts[operation];\n else scripts[operation] = answer;\n },\n async model(_authorization, request) {\n return resolveScript(\n scripts.model as Script<ModelResult, typeof request> | undefined,\n () =>\n rooms.find((room) => room.locator === request.locator)?.model ?? {\n kind: 'model-unavailable',\n reason: 'not-readable',\n },\n request,\n );\n },\n async authorize() {\n return resolveScript<Authorization, void>(\n scripts.authorize as Script<Authorization, void> | undefined,\n () => ({}),\n undefined,\n );\n },\n async discover(_authorization: Authorization) {\n return resolveScript<DiscoverResult, void>(\n scripts.discover as Script<DiscoverResult, void> | undefined,\n discovery,\n undefined,\n );\n },\n async bootstrap(_authorization: Authorization, request: BootstrapRequest) {\n return resolveScript<BootstrapResult, BootstrapRequest>(\n scripts.bootstrap as Script<BootstrapResult, BootstrapRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));\n },\n request,\n );\n },\n async refresh(_authorization: Authorization, request: RefreshRequest) {\n return resolveScript<RefreshResult, RefreshRequest>(\n scripts.refresh as Script<RefreshResult, RefreshRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n if (request.pageToken !== undefined) {\n const continuation = refreshPages.get(request.pageToken);\n if (\n continuation === undefined ||\n continuation.room.locator !== request.locator ||\n continuation.from.roomVersion !== request.fromRoomVersion\n ) {\n throw new Error('Invalid Refresh Page Token');\n }\n return advancement(continuation.room, continuation.from, continuation.at);\n }\n if (request.fromRoomVersion === room.roomVersion) {\n return { kind: 'still-current' };\n }\n const from = served.get(room.locator)?.get(request.fromRoomVersion);\n if (from === undefined) return { kind: 'beyond-horizon' };\n return advancement(room, from, 0);\n },\n request,\n );\n },\n async mutate(_authorization: Authorization, request: MutationRequest) {\n return resolveScript<MutationResult, MutationRequest>(\n scripts.mutate as Script<MutationResult, MutationRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n return { kind: 'rejected', text: '', affected: {} };\n },\n request,\n );\n },\n async history(_authorization: Authorization, request: HistoryRequest) {\n return resolveScript<HistoryResult, HistoryRequest>(\n scripts.history as Script<HistoryResult, HistoryRequest> | undefined,\n () => {\n const room = rooms.find((entry) => entry.locator === request.locator);\n if (room === undefined) {\n return { kind: 'room-not-readable', locator: request.locator };\n }\n return {\n kind: 'history',\n revisions: [],\n };\n },\n request,\n );\n },\n async action(_authorization: Authorization, request: ActionRequest) {\n return resolveScript<ActionResult, ActionRequest>(\n scripts.action as Script<ActionResult, ActionRequest> | undefined,\n () => ({\n kind: 'rejected',\n text: '',\n }),\n request,\n );\n },\n };\n}\n"],"names":["ROOM_CONTRACT_VERSION","MD_MODEL","FIXTURE_RETENTION","history","kind","seconds","outcome","refreshHorizon","declaredRetention","value","retention","Number","isFinite","Error","named","source","paths","taken","path","undefined","resolveScript","answer","fallback","request","createMemoryAdapter","options","rooms","mdModel","supportedVersions","capabilities","providerLimits","origins","pageSize","scripts","served","Map","refreshPages","retain","entries","room","versions","get","locator","set","roomVersion","declared","name","collectionRoot","operations","replica","attachedModel","providerOwnedPaths","page","from","Object","keys","documents","sort","size","length","slice","next","revisions","binaryTargets","pageToken","String","advancement","at","current","previous","currentTargets","Set","previousTargets","changed","filter","opening","target","has","removals","discovery","map","setRooms","script","operation","model","_authorization","find","reason","authorize","discover","bootstrap","entry","refresh","continuation","fromRoomVersion","mutate","text","affected","action"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { Validation } from '@agentshouse/mdmodel';
2
+ import type { MdType } from './collection.js';
3
+ export type ModelIdentity = {
4
+ identity: string;
5
+ version: string;
6
+ };
7
+ export type ModelSnapshot = ModelIdentity & {
8
+ definitions: Readonly<Record<string, string>>;
9
+ };
10
+ export type ModelUnavailableReason = 'not-readable' | 'revoked' | 'not-acquired' | 'version-changed' | 'invalid' | 'binding-unavailable';
11
+ export type ModelResult = {
12
+ kind: 'model';
13
+ snapshot: ModelSnapshot;
14
+ } | {
15
+ kind: 'model-unavailable';
16
+ reason: ModelUnavailableReason;
17
+ } | {
18
+ kind: 'transport-uncertainty';
19
+ } | {
20
+ kind: 'revoked-authorization';
21
+ };
22
+ export type ModelState = {
23
+ status: 'unavailable';
24
+ reason: ModelUnavailableReason;
25
+ } | {
26
+ status: 'current' | 'cached';
27
+ snapshot: ModelSnapshot;
28
+ verifiedWith: ModelIdentity;
29
+ types: readonly MdType[];
30
+ };
31
+ export type TypesResult = {
32
+ status: 'unavailable';
33
+ reason: ModelUnavailableReason;
34
+ } | {
35
+ status: 'current' | 'cached';
36
+ identity: string;
37
+ version: string;
38
+ verifiedWith: ModelIdentity;
39
+ types: readonly MdType[];
40
+ };
41
+ export type ModelValidation = {
42
+ verdict: 'accept';
43
+ } | (Extract<Validation, {
44
+ verdict: 'refuse';
45
+ }> & {
46
+ source: 'content' | 'model';
47
+ });
48
+ export type AttachedModelBinding = {
49
+ verify(snapshot: ModelSnapshot): {
50
+ kind: 'verified';
51
+ types: readonly MdType[];
52
+ } | {
53
+ kind: 'invalid';
54
+ };
55
+ validate(input: {
56
+ model: ModelSnapshot;
57
+ documents: Readonly<Record<string, string>>;
58
+ binaryTargets: readonly string[];
59
+ }): ModelValidation;
60
+ };
61
+ export type ValidationReceipt = {
62
+ identity: string;
63
+ version: string;
64
+ source: 'current' | 'cached';
65
+ };
66
+ export declare const NO_MODEL: ModelState;
67
+ export declare function modelTypes(state: ModelState): TypesResult;
68
+ export declare function cached(state: ModelState): ModelState;
69
+ export declare function sameModel(left: ModelIdentity, right: ModelIdentity): boolean;
70
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,CAAC;AAC9F,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,SAAS,GACT,qBAAqB,CAAC;AAC1B,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,CAAC;AACtC,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AACN,MAAM,MAAM,eAAe,GACvB;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,GACrB,CAAC,OAAO,CAAC,UAAU,EAAE;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC,GAAG;IAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAA;CAAE,CAAC,CAAC;AACnF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,CACJ,QAAQ,EAAE,aAAa,GACtB;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC;IACxE,QAAQ,CAAC,KAAK,EAAE;QACd,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5C,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;KAClC,GAAG,eAAe,CAAC;CACrB,CAAC;AACF,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC;AACpG,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAUzD;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E"}
package/dist/model.js ADDED
@@ -0,0 +1,28 @@
1
+ export const NO_MODEL = {
2
+ status: 'unavailable',
3
+ reason: 'not-acquired'
4
+ };
5
+ export function modelTypes(state) {
6
+ return state.status === 'unavailable' ? {
7
+ ...state
8
+ } : {
9
+ status: state.status,
10
+ identity: state.snapshot.identity,
11
+ version: state.snapshot.version,
12
+ verifiedWith: {
13
+ ...state.verifiedWith
14
+ },
15
+ types: structuredClone(state.types)
16
+ };
17
+ }
18
+ export function cached(state) {
19
+ return state.status === 'unavailable' ? state : {
20
+ ...state,
21
+ status: 'cached'
22
+ };
23
+ }
24
+ export function sameModel(left, right) {
25
+ return left.identity === right.identity && left.version === right.version;
26
+ }
27
+
28
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/model.ts"],"sourcesContent":["import type { Validation } from '@agentshouse/mdmodel';\nimport type { MdType } from './collection.js';\n\nexport type ModelIdentity = { identity: string; version: string };\nexport type ModelSnapshot = ModelIdentity & { definitions: Readonly<Record<string, string>> };\nexport type ModelUnavailableReason =\n | 'not-readable'\n | 'revoked'\n | 'not-acquired'\n | 'version-changed'\n | 'invalid'\n | 'binding-unavailable';\nexport type ModelResult =\n | { kind: 'model'; snapshot: ModelSnapshot }\n | { kind: 'model-unavailable'; reason: ModelUnavailableReason }\n | { kind: 'transport-uncertainty' }\n | { kind: 'revoked-authorization' };\nexport type ModelState =\n | { status: 'unavailable'; reason: ModelUnavailableReason }\n | {\n status: 'current' | 'cached';\n snapshot: ModelSnapshot;\n verifiedWith: ModelIdentity;\n types: readonly MdType[];\n };\nexport type TypesResult =\n | { status: 'unavailable'; reason: ModelUnavailableReason }\n | {\n status: 'current' | 'cached';\n identity: string;\n version: string;\n verifiedWith: ModelIdentity;\n types: readonly MdType[];\n };\nexport type ModelValidation =\n | { verdict: 'accept' }\n | (Extract<Validation, { verdict: 'refuse' }> & { source: 'content' | 'model' });\nexport type AttachedModelBinding = {\n verify(\n snapshot: ModelSnapshot,\n ): { kind: 'verified'; types: readonly MdType[] } | { kind: 'invalid' };\n validate(input: {\n model: ModelSnapshot;\n documents: Readonly<Record<string, string>>;\n binaryTargets: readonly string[];\n }): ModelValidation;\n};\nexport type ValidationReceipt = { identity: string; version: string; source: 'current' | 'cached' };\nexport const NO_MODEL: ModelState = { status: 'unavailable', reason: 'not-acquired' };\nexport function modelTypes(state: ModelState): TypesResult {\n return state.status === 'unavailable'\n ? { ...state }\n : {\n status: state.status,\n identity: state.snapshot.identity,\n version: state.snapshot.version,\n verifiedWith: { ...state.verifiedWith },\n types: structuredClone(state.types),\n };\n}\nexport function cached(state: ModelState): ModelState {\n return state.status === 'unavailable' ? state : { ...state, status: 'cached' };\n}\nexport function sameModel(left: ModelIdentity, right: ModelIdentity): boolean {\n return left.identity === right.identity && left.version === right.version;\n}\n"],"names":["NO_MODEL","status","reason","modelTypes","state","identity","snapshot","version","verifiedWith","types","structuredClone","cached","sameModel","left","right"],"mappings":"AAgDA,OAAO,MAAMA,WAAuB;IAAEC,QAAQ;IAAeC,QAAQ;AAAe,EAAE;AACtF,OAAO,SAASC,WAAWC,KAAiB;IAC1C,OAAOA,MAAMH,MAAM,KAAK,gBACpB;QAAE,GAAGG,KAAK;IAAC,IACX;QACEH,QAAQG,MAAMH,MAAM;QACpBI,UAAUD,MAAME,QAAQ,CAACD,QAAQ;QACjCE,SAASH,MAAME,QAAQ,CAACC,OAAO;QAC/BC,cAAc;YAAE,GAAGJ,MAAMI,YAAY;QAAC;QACtCC,OAAOC,gBAAgBN,MAAMK,KAAK;IACpC;AACN;AACA,OAAO,SAASE,OAAOP,KAAiB;IACtC,OAAOA,MAAMH,MAAM,KAAK,gBAAgBG,QAAQ;QAAE,GAAGA,KAAK;QAAEH,QAAQ;IAAS;AAC/E;AACA,OAAO,SAASW,UAAUC,IAAmB,EAAEC,KAAoB;IACjE,OAAOD,KAAKR,QAAQ,KAAKS,MAAMT,QAAQ,IAAIQ,KAAKN,OAAO,KAAKO,MAAMP,OAAO;AAC3E"}
@@ -0,0 +1,12 @@
1
+ import type { QueryOptions, QueryResult } from '@agentshouse/query';
2
+ import type { Document } from '@agentshouse/mdmodel';
3
+ import type { TypesResult } from './model.js';
4
+ export type QueryInput = {
5
+ room: string;
6
+ roomVersion: string;
7
+ documents: Readonly<Record<string, Document>>;
8
+ model: TypesResult;
9
+ };
10
+ export type QueryBinding = (rooms: readonly QueryInput[], options: QueryOptions) => QueryResult;
11
+ export declare function rawQuery(rooms: readonly QueryInput[]): QueryResult;
12
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AACF,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,EAAE,YAAY,KAAK,WAAW,CAAC;AAChG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,WAAW,CAgBlE"}
package/dist/query.js ADDED
@@ -0,0 +1,18 @@
1
+ export function rawQuery(rooms) {
2
+ return {
3
+ roomVersions: Object.fromEntries(rooms.map((room)=>[
4
+ room.room,
5
+ room.roomVersion
6
+ ])),
7
+ groups: null,
8
+ documents: rooms.flatMap((room)=>Object.entries(room.documents).filter(([path])=>path.endsWith('.md')).map(([path, document])=>({
9
+ ...structuredClone(document),
10
+ type: document.type ?? 'any',
11
+ room: room.room,
12
+ path,
13
+ backlinks: []
14
+ })))
15
+ };
16
+ }
17
+
18
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/query.ts"],"sourcesContent":["import type { QueryOptions, QueryResult } from '@agentshouse/query';\nimport type { Document } from '@agentshouse/mdmodel';\nimport type { TypesResult } from './model.js';\n\nexport type QueryInput = {\n room: string;\n roomVersion: string;\n documents: Readonly<Record<string, Document>>;\n model: TypesResult;\n};\nexport type QueryBinding = (rooms: readonly QueryInput[], options: QueryOptions) => QueryResult;\nexport function rawQuery(rooms: readonly QueryInput[]): QueryResult {\n return {\n roomVersions: Object.fromEntries(rooms.map((room) => [room.room, room.roomVersion])),\n groups: null,\n documents: rooms.flatMap((room) =>\n Object.entries(room.documents)\n .filter(([path]) => path.endsWith('.md'))\n .map(([path, document]) => ({\n ...structuredClone(document),\n type: document.type ?? 'any',\n room: room.room,\n path,\n backlinks: [],\n })),\n ),\n };\n}\n"],"names":["rawQuery","rooms","roomVersions","Object","fromEntries","map","room","roomVersion","groups","documents","flatMap","entries","filter","path","endsWith","document","structuredClone","type","backlinks"],"mappings":"AAWA,OAAO,SAASA,SAASC,KAA4B;IACnD,OAAO;QACLC,cAAcC,OAAOC,WAAW,CAACH,MAAMI,GAAG,CAAC,CAACC,OAAS;gBAACA,KAAKA,IAAI;gBAAEA,KAAKC,WAAW;aAAC;QAClFC,QAAQ;QACRC,WAAWR,MAAMS,OAAO,CAAC,CAACJ,OACxBH,OAAOQ,OAAO,CAACL,KAAKG,SAAS,EAC1BG,MAAM,CAAC,CAAC,CAACC,KAAK,GAAKA,KAAKC,QAAQ,CAAC,QACjCT,GAAG,CAAC,CAAC,CAACQ,MAAME,SAAS,GAAM,CAAA;oBAC1B,GAAGC,gBAAgBD,SAAS;oBAC5BE,MAAMF,SAASE,IAAI,IAAI;oBACvBX,MAAMA,KAAKA,IAAI;oBACfO;oBACAK,WAAW,EAAE;gBACf,CAAA;IAEN;AACF"}
package/dist/refresh.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { AttachedModelBinding } from './model.js';
1
2
  import type { Adapter, AdapterFailure, Authorization } from './adapter.js';
2
3
  import { type ConfirmedLayer } from './replica.js';
3
4
  import { type Unconfirmed } from './transfer.js';
@@ -9,5 +10,5 @@ export type RefreshOutcome = {
9
10
  } | {
10
11
  kind: 'beyond-horizon';
11
12
  } | Unconfirmed | AdapterFailure;
12
- export declare function refreshRoom(adapter: Adapter, authorization: Authorization, confirmed: ConfirmedLayer): Promise<RefreshOutcome>;
13
+ export declare function refreshRoom(adapter: Adapter, authorization: Authorization, confirmed: ConfirmedLayer, binding: AttachedModelBinding | null): Promise<RefreshOutcome>;
13
14
  //# sourceMappingURL=refresh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAe,MAAM,cAAc,CAAC;AACxF,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,WAAW,GACX,cAAc,CAAC;AAEnB,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,cAAc,CAAC,CA0CzB"}
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAe,MAAM,cAAc,CAAC;AACxF,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,cAAc,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B,WAAW,GACX,cAAc,CAAC;AAEnB,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE,oBAAoB,GAAG,IAAI,GACnC,OAAO,CAAC,cAAc,CAAC,CAsDzB"}
package/dist/refresh.js CHANGED
@@ -1,10 +1,11 @@
1
- import { readConfirmed } from './replica.js';
1
+ import { readStaged } from './replica.js';
2
2
  import { unconfirmed } from './transfer.js';
3
- export async function refreshRoom(adapter, authorization, confirmed) {
3
+ export async function refreshRoom(adapter, authorization, confirmed, binding) {
4
4
  const locator = confirmed.record.locator;
5
5
  const fromRoomVersion = confirmed.record.roomVersion;
6
6
  const first = await adapter.refresh(authorization, {
7
7
  locator,
8
+ selection: confirmed.record.replica.selection,
8
9
  fromRoomVersion
9
10
  });
10
11
  if (first.kind !== 'net-advancement') return first;
@@ -36,6 +37,7 @@ export async function refreshRoom(adapter, authorization, confirmed) {
36
37
  while(pageToken !== undefined){
37
38
  const page = await adapter.refresh(authorization, {
38
39
  locator,
40
+ selection: confirmed.record.replica.selection,
39
41
  fromRoomVersion,
40
42
  pageToken
41
43
  });
@@ -45,7 +47,7 @@ export async function refreshRoom(adapter, authorization, confirmed) {
45
47
  stage(page);
46
48
  pageToken = page.pageToken;
47
49
  }
48
- const advanced = readConfirmed({
50
+ const advanced = readStaged({
49
51
  ...confirmed.record,
50
52
  roomVersion,
51
53
  documents,
@@ -53,7 +55,7 @@ export async function refreshRoom(adapter, authorization, confirmed) {
53
55
  ...binaryTargets
54
56
  ].sort(),
55
57
  revisions
56
- });
58
+ }, binding);
57
59
  return advanced === null ? unconfirmed : {
58
60
  kind: 'advanced',
59
61
  confirmed: advanced
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdruntime/src/refresh.ts"],"sourcesContent":["import type { Adapter, AdapterFailure, Authorization, RefreshPage } from './adapter.js';\nimport { readConfirmed, type ConfirmedLayer } from './replica.js';\nimport { unconfirmed, type Unconfirmed } from './transfer.js';\n\nexport type RefreshOutcome =\n | { kind: 'still-current' }\n | { kind: 'advanced'; confirmed: ConfirmedLayer }\n | { kind: 'beyond-horizon' }\n | Unconfirmed\n | AdapterFailure;\n\nexport async function refreshRoom(\n adapter: Adapter,\n authorization: Authorization,\n confirmed: ConfirmedLayer,\n): Promise<RefreshOutcome> {\n const locator = confirmed.record.locator;\n const fromRoomVersion = confirmed.record.roomVersion;\n const first = await adapter.refresh(authorization, { locator, fromRoomVersion });\n if (first.kind !== 'net-advancement') return first;\n const roomVersion = first.roomVersion;\n const documents: Record<string, string> = { ...confirmed.record.documents };\n const revisions: Record<string, string> = { ...confirmed.record.revisions };\n const binaryTargets = new Set(confirmed.record.binaryTargets);\n const stage = (page: RefreshPage) => {\n Object.assign(documents, page.documents);\n Object.assign(revisions, page.revisions);\n for (const path of Object.keys(page.documents)) binaryTargets.delete(path);\n for (const target of page.binaryTargets) {\n delete documents[target];\n delete revisions[target];\n binaryTargets.add(target);\n }\n for (const path of page.removals) {\n delete documents[path];\n delete revisions[path];\n binaryTargets.delete(path);\n }\n };\n stage(first);\n let pageToken = first.pageToken;\n while (pageToken !== undefined) {\n const page = await adapter.refresh(authorization, { locator, fromRoomVersion, pageToken });\n if (page.kind === 'still-current' || page.kind === 'beyond-horizon') return unconfirmed;\n if (page.kind !== 'net-advancement') return page;\n if (page.roomVersion !== roomVersion) return unconfirmed;\n stage(page);\n pageToken = page.pageToken;\n }\n const advanced = readConfirmed({\n ...confirmed.record,\n roomVersion,\n documents,\n binaryTargets: [...binaryTargets].sort(),\n revisions,\n });\n return advanced === null ? unconfirmed : { kind: 'advanced', confirmed: advanced };\n}\n"],"names":["readConfirmed","unconfirmed","refreshRoom","adapter","authorization","confirmed","locator","record","fromRoomVersion","roomVersion","first","refresh","kind","documents","revisions","binaryTargets","Set","stage","page","Object","assign","path","keys","delete","target","add","removals","pageToken","undefined","advanced","sort"],"mappings":"AACA,SAASA,aAAa,QAA6B,eAAe;AAClE,SAASC,WAAW,QAA0B,gBAAgB;AAS9D,OAAO,eAAeC,YACpBC,OAAgB,EAChBC,aAA4B,EAC5BC,SAAyB;IAEzB,MAAMC,UAAUD,UAAUE,MAAM,CAACD,OAAO;IACxC,MAAME,kBAAkBH,UAAUE,MAAM,CAACE,WAAW;IACpD,MAAMC,QAAQ,MAAMP,QAAQQ,OAAO,CAACP,eAAe;QAAEE;QAASE;IAAgB;IAC9E,IAAIE,MAAME,IAAI,KAAK,mBAAmB,OAAOF;IAC7C,MAAMD,cAAcC,MAAMD,WAAW;IACrC,MAAMI,YAAoC;QAAE,GAAGR,UAAUE,MAAM,CAACM,SAAS;IAAC;IAC1E,MAAMC,YAAoC;QAAE,GAAGT,UAAUE,MAAM,CAACO,SAAS;IAAC;IAC1E,MAAMC,gBAAgB,IAAIC,IAAIX,UAAUE,MAAM,CAACQ,aAAa;IAC5D,MAAME,QAAQ,CAACC;QACbC,OAAOC,MAAM,CAACP,WAAWK,KAAKL,SAAS;QACvCM,OAAOC,MAAM,CAACN,WAAWI,KAAKJ,SAAS;QACvC,KAAK,MAAMO,QAAQF,OAAOG,IAAI,CAACJ,KAAKL,SAAS,EAAGE,cAAcQ,MAAM,CAACF;QACrE,KAAK,MAAMG,UAAUN,KAAKH,aAAa,CAAE;YACvC,OAAOF,SAAS,CAACW,OAAO;YACxB,OAAOV,SAAS,CAACU,OAAO;YACxBT,cAAcU,GAAG,CAACD;QACpB;QACA,KAAK,MAAMH,QAAQH,KAAKQ,QAAQ,CAAE;YAChC,OAAOb,SAAS,CAACQ,KAAK;YACtB,OAAOP,SAAS,CAACO,KAAK;YACtBN,cAAcQ,MAAM,CAACF;QACvB;IACF;IACAJ,MAAMP;IACN,IAAIiB,YAAYjB,MAAMiB,SAAS;IAC/B,MAAOA,cAAcC,UAAW;QAC9B,MAAMV,OAAO,MAAMf,QAAQQ,OAAO,CAACP,eAAe;YAAEE;YAASE;YAAiBmB;QAAU;QACxF,IAAIT,KAAKN,IAAI,KAAK,mBAAmBM,KAAKN,IAAI,KAAK,kBAAkB,OAAOX;QAC5E,IAAIiB,KAAKN,IAAI,KAAK,mBAAmB,OAAOM;QAC5C,IAAIA,KAAKT,WAAW,KAAKA,aAAa,OAAOR;QAC7CgB,MAAMC;QACNS,YAAYT,KAAKS,SAAS;IAC5B;IACA,MAAME,WAAW7B,cAAc;QAC7B,GAAGK,UAAUE,MAAM;QACnBE;QACAI;QACAE,eAAe;eAAIA;SAAc,CAACe,IAAI;QACtChB;IACF;IACA,OAAOe,aAAa,OAAO5B,cAAc;QAAEW,MAAM;QAAYP,WAAWwB;IAAS;AACnF"}
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/refresh.ts"],"sourcesContent":["import type { AttachedModelBinding } from './model.js';\nimport type { Adapter, AdapterFailure, Authorization, RefreshPage } from './adapter.js';\nimport { readStaged, type ConfirmedLayer } from './replica.js';\nimport { unconfirmed, type Unconfirmed } from './transfer.js';\n\nexport type RefreshOutcome =\n | { kind: 'still-current' }\n | { kind: 'advanced'; confirmed: ConfirmedLayer }\n | { kind: 'beyond-horizon' }\n | Unconfirmed\n | AdapterFailure;\n\nexport async function refreshRoom(\n adapter: Adapter,\n authorization: Authorization,\n confirmed: ConfirmedLayer,\n binding: AttachedModelBinding | null,\n): Promise<RefreshOutcome> {\n const locator = confirmed.record.locator;\n const fromRoomVersion = confirmed.record.roomVersion;\n const first = await adapter.refresh(authorization, {\n locator,\n selection: confirmed.record.replica.selection,\n fromRoomVersion,\n });\n if (first.kind !== 'net-advancement') return first;\n const roomVersion = first.roomVersion;\n const documents: Record<string, string> = { ...confirmed.record.documents };\n const revisions: Record<string, string> = { ...confirmed.record.revisions };\n const binaryTargets = new Set(confirmed.record.binaryTargets);\n const stage = (page: RefreshPage) => {\n Object.assign(documents, page.documents);\n Object.assign(revisions, page.revisions);\n for (const path of Object.keys(page.documents)) binaryTargets.delete(path);\n for (const target of page.binaryTargets) {\n delete documents[target];\n delete revisions[target];\n binaryTargets.add(target);\n }\n for (const path of page.removals) {\n delete documents[path];\n delete revisions[path];\n binaryTargets.delete(path);\n }\n };\n stage(first);\n let pageToken = first.pageToken;\n while (pageToken !== undefined) {\n const page = await adapter.refresh(authorization, {\n locator,\n selection: confirmed.record.replica.selection,\n fromRoomVersion,\n pageToken,\n });\n if (page.kind === 'still-current' || page.kind === 'beyond-horizon') return unconfirmed;\n if (page.kind !== 'net-advancement') return page;\n if (page.roomVersion !== roomVersion) return unconfirmed;\n stage(page);\n pageToken = page.pageToken;\n }\n const advanced = readStaged(\n {\n ...confirmed.record,\n roomVersion,\n documents,\n binaryTargets: [...binaryTargets].sort(),\n revisions,\n },\n binding,\n );\n return advanced === null ? unconfirmed : { kind: 'advanced', confirmed: advanced };\n}\n"],"names":["readStaged","unconfirmed","refreshRoom","adapter","authorization","confirmed","binding","locator","record","fromRoomVersion","roomVersion","first","refresh","selection","replica","kind","documents","revisions","binaryTargets","Set","stage","page","Object","assign","path","keys","delete","target","add","removals","pageToken","undefined","advanced","sort"],"mappings":"AAEA,SAASA,UAAU,QAA6B,eAAe;AAC/D,SAASC,WAAW,QAA0B,gBAAgB;AAS9D,OAAO,eAAeC,YACpBC,OAAgB,EAChBC,aAA4B,EAC5BC,SAAyB,EACzBC,OAAoC;IAEpC,MAAMC,UAAUF,UAAUG,MAAM,CAACD,OAAO;IACxC,MAAME,kBAAkBJ,UAAUG,MAAM,CAACE,WAAW;IACpD,MAAMC,QAAQ,MAAMR,QAAQS,OAAO,CAACR,eAAe;QACjDG;QACAM,WAAWR,UAAUG,MAAM,CAACM,OAAO,CAACD,SAAS;QAC7CJ;IACF;IACA,IAAIE,MAAMI,IAAI,KAAK,mBAAmB,OAAOJ;IAC7C,MAAMD,cAAcC,MAAMD,WAAW;IACrC,MAAMM,YAAoC;QAAE,GAAGX,UAAUG,MAAM,CAACQ,SAAS;IAAC;IAC1E,MAAMC,YAAoC;QAAE,GAAGZ,UAAUG,MAAM,CAACS,SAAS;IAAC;IAC1E,MAAMC,gBAAgB,IAAIC,IAAId,UAAUG,MAAM,CAACU,aAAa;IAC5D,MAAME,QAAQ,CAACC;QACbC,OAAOC,MAAM,CAACP,WAAWK,KAAKL,SAAS;QACvCM,OAAOC,MAAM,CAACN,WAAWI,KAAKJ,SAAS;QACvC,KAAK,MAAMO,QAAQF,OAAOG,IAAI,CAACJ,KAAKL,SAAS,EAAGE,cAAcQ,MAAM,CAACF;QACrE,KAAK,MAAMG,UAAUN,KAAKH,aAAa,CAAE;YACvC,OAAOF,SAAS,CAACW,OAAO;YACxB,OAAOV,SAAS,CAACU,OAAO;YACxBT,cAAcU,GAAG,CAACD;QACpB;QACA,KAAK,MAAMH,QAAQH,KAAKQ,QAAQ,CAAE;YAChC,OAAOb,SAAS,CAACQ,KAAK;YACtB,OAAOP,SAAS,CAACO,KAAK;YACtBN,cAAcQ,MAAM,CAACF;QACvB;IACF;IACAJ,MAAMT;IACN,IAAImB,YAAYnB,MAAMmB,SAAS;IAC/B,MAAOA,cAAcC,UAAW;QAC9B,MAAMV,OAAO,MAAMlB,QAAQS,OAAO,CAACR,eAAe;YAChDG;YACAM,WAAWR,UAAUG,MAAM,CAACM,OAAO,CAACD,SAAS;YAC7CJ;YACAqB;QACF;QACA,IAAIT,KAAKN,IAAI,KAAK,mBAAmBM,KAAKN,IAAI,KAAK,kBAAkB,OAAOd;QAC5E,IAAIoB,KAAKN,IAAI,KAAK,mBAAmB,OAAOM;QAC5C,IAAIA,KAAKX,WAAW,KAAKA,aAAa,OAAOT;QAC7CmB,MAAMC;QACNS,YAAYT,KAAKS,SAAS;IAC5B;IACA,MAAME,WAAWhC,WACf;QACE,GAAGK,UAAUG,MAAM;QACnBE;QACAM;QACAE,eAAe;eAAIA;SAAc,CAACe,IAAI;QACtChB;IACF,GACAX;IAEF,OAAO0B,aAAa,OAAO/B,cAAc;QAAEc,MAAM;QAAYV,WAAW2B;IAAS;AACnF"}
package/dist/replica.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { AttachedModelBinding } from './model.js';
1
2
  import { type ChangeBatch } from './change.js';
2
3
  import { type Collection } from './collection.js';
3
4
  import { type Layer } from './overlay.js';
@@ -15,6 +16,7 @@ export type Replica = {
15
16
  visible: VisibleLayer;
16
17
  };
17
18
  export declare function readConfirmed(record: ReplicaRecord): ConfirmedLayer | null;
18
- export declare function applyReturned(confirmed: ConfirmedLayer, documents: Readonly<Record<string, string>>, revisions: Readonly<Record<string, string>>, removals: readonly string[], roomVersion: string): ConfirmedLayer | null;
19
+ export declare function readStaged(record: ReplicaRecord, binding: AttachedModelBinding | null): ConfirmedLayer | null;
20
+ export declare function applyReturned(confirmed: ConfirmedLayer, documents: Readonly<Record<string, string>>, revisions: Readonly<Record<string, string>>, removals: readonly string[], roomVersion: string, binding: AttachedModelBinding | null): ConfirmedLayer | null;
19
21
  export declare function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[]): Replica;
20
22
  //# sourceMappingURL=replica.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9B,OAAO,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CAG1E;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,MAAM,GAClB,cAAc,GAAG,IAAI,CAgBvB;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAoB3F"}
1
+ {"version":3,"file":"replica.d.ts","sourceRoot":"","sources":["../src/replica.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAIL,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAW,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG;IACjC,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,SAAS,EAAE,cAAc,CAAC;IAC1B,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9B,OAAO,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,GAAG,IAAI,CAG1E;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,oBAAoB,GAAG,IAAI,GACnC,cAAc,GAAG,IAAI,CAcvB;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAC3C,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,oBAAoB,GAAG,IAAI,GACnC,cAAc,GAAG,IAAI,CAmBvB;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,OAAO,CAuB3F"}
package/dist/replica.js CHANGED
@@ -1,14 +1,18 @@
1
1
  import { immutable } from './change.js';
2
- import { parseCollection, readCollection } from './collection.js';
2
+ import { parseCollection, readCollection, validateCollection } from './collection.js';
3
3
  import { overlay } from './overlay.js';
4
4
  export function readConfirmed(record) {
5
- const collection = readCollection(record.documents, record.binaryTargets);
5
+ const collection = readCollection(record.documents, record.collectionRoot, record.model);
6
6
  return collection === null ? null : {
7
7
  record,
8
8
  collection
9
9
  };
10
10
  }
11
- export function applyReturned(confirmed, documents, revisions, removals, roomVersion) {
11
+ export function readStaged(record, binding) {
12
+ if (record.model.status === 'current' && binding !== null && validateCollection(record.documents, record.binaryTargets, record.collectionRoot, record.model, binding).verdict === 'refuse') return null;
13
+ return readConfirmed(record);
14
+ }
15
+ export function applyReturned(confirmed, documents, revisions, removals, roomVersion, binding) {
12
16
  const nextDocuments = {
13
17
  ...confirmed.record.documents,
14
18
  ...documents
@@ -23,7 +27,7 @@ export function applyReturned(confirmed, documents, revisions, removals, roomVer
23
27
  delete nextRevisions[path];
24
28
  binaryTargets.delete(path);
25
29
  }
26
- return readConfirmed({
30
+ return readStaged({
27
31
  ...confirmed.record,
28
32
  roomVersion,
29
33
  documents: nextDocuments,
@@ -31,7 +35,7 @@ export function applyReturned(confirmed, documents, revisions, removals, roomVer
31
35
  binaryTargets: [
32
36
  ...binaryTargets
33
37
  ].sort()
34
- });
38
+ }, binding);
35
39
  }
36
40
  export function replicaOf(confirmed, queue) {
37
41
  const batches = Object.freeze(queue.map(immutable));
@@ -53,7 +57,7 @@ export function replicaOf(confirmed, queue) {
53
57
  queue: batches,
54
58
  visible: {
55
59
  ...layer,
56
- collection: parseCollection(layer.documents)
60
+ collection: parseCollection(layer.documents, confirmed.record.model)
57
61
  }
58
62
  };
59
63
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdruntime/src/replica.ts"],"sourcesContent":["import { immutable, type ChangeBatch } from './change.js';\nimport { parseCollection, readCollection, type Collection } from './collection.js';\nimport { overlay, type Layer } from './overlay.js';\nimport type { ReplicaRecord } from './store.js';\n\nexport type ConfirmedLayer = {\n record: ReplicaRecord;\n collection: Collection;\n};\n\nexport type VisibleLayer = Layer & {\n collection: Collection;\n};\n\nexport type Replica = {\n confirmed: ConfirmedLayer;\n queue: readonly ChangeBatch[];\n visible: VisibleLayer;\n};\n\nexport function readConfirmed(record: ReplicaRecord): ConfirmedLayer | null {\n const collection = readCollection(record.documents, record.binaryTargets);\n return collection === null ? null : { record, collection };\n}\n\nexport function applyReturned(\n confirmed: ConfirmedLayer,\n documents: Readonly<Record<string, string>>,\n revisions: Readonly<Record<string, string>>,\n removals: readonly string[],\n roomVersion: string,\n): ConfirmedLayer | null {\n const nextDocuments = { ...confirmed.record.documents, ...documents };\n const nextRevisions = { ...confirmed.record.revisions, ...revisions };\n const binaryTargets = new Set(confirmed.record.binaryTargets);\n for (const path of removals) {\n delete nextDocuments[path];\n delete nextRevisions[path];\n binaryTargets.delete(path);\n }\n return readConfirmed({\n ...confirmed.record,\n roomVersion,\n documents: nextDocuments,\n revisions: nextRevisions,\n binaryTargets: [...binaryTargets].sort(),\n });\n}\n\nexport function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[]): Replica {\n const batches = Object.freeze(queue.map(immutable));\n if (batches.length === 0) {\n return {\n confirmed,\n queue: batches,\n visible: {\n documents: confirmed.record.documents,\n binaryTargets: confirmed.record.binaryTargets,\n revisions: confirmed.record.revisions,\n collection: confirmed.collection,\n },\n };\n }\n const layer = overlay(confirmed.record, batches);\n return {\n confirmed,\n queue: batches,\n visible: { ...layer, collection: parseCollection(layer.documents) },\n };\n}\n"],"names":["immutable","parseCollection","readCollection","overlay","readConfirmed","record","collection","documents","binaryTargets","applyReturned","confirmed","revisions","removals","roomVersion","nextDocuments","nextRevisions","Set","path","delete","sort","replicaOf","queue","batches","Object","freeze","map","length","visible","layer"],"mappings":"AAAA,SAASA,SAAS,QAA0B,cAAc;AAC1D,SAASC,eAAe,EAAEC,cAAc,QAAyB,kBAAkB;AACnF,SAASC,OAAO,QAAoB,eAAe;AAkBnD,OAAO,SAASC,cAAcC,MAAqB;IACjD,MAAMC,aAAaJ,eAAeG,OAAOE,SAAS,EAAEF,OAAOG,aAAa;IACxE,OAAOF,eAAe,OAAO,OAAO;QAAED;QAAQC;IAAW;AAC3D;AAEA,OAAO,SAASG,cACdC,SAAyB,EACzBH,SAA2C,EAC3CI,SAA2C,EAC3CC,QAA2B,EAC3BC,WAAmB;IAEnB,MAAMC,gBAAgB;QAAE,GAAGJ,UAAUL,MAAM,CAACE,SAAS;QAAE,GAAGA,SAAS;IAAC;IACpE,MAAMQ,gBAAgB;QAAE,GAAGL,UAAUL,MAAM,CAACM,SAAS;QAAE,GAAGA,SAAS;IAAC;IACpE,MAAMH,gBAAgB,IAAIQ,IAAIN,UAAUL,MAAM,CAACG,aAAa;IAC5D,KAAK,MAAMS,QAAQL,SAAU;QAC3B,OAAOE,aAAa,CAACG,KAAK;QAC1B,OAAOF,aAAa,CAACE,KAAK;QAC1BT,cAAcU,MAAM,CAACD;IACvB;IACA,OAAOb,cAAc;QACnB,GAAGM,UAAUL,MAAM;QACnBQ;QACAN,WAAWO;QACXH,WAAWI;QACXP,eAAe;eAAIA;SAAc,CAACW,IAAI;IACxC;AACF;AAEA,OAAO,SAASC,UAAUV,SAAyB,EAAEW,KAA6B;IAChF,MAAMC,UAAUC,OAAOC,MAAM,CAACH,MAAMI,GAAG,CAACzB;IACxC,IAAIsB,QAAQI,MAAM,KAAK,GAAG;QACxB,OAAO;YACLhB;YACAW,OAAOC;YACPK,SAAS;gBACPpB,WAAWG,UAAUL,MAAM,CAACE,SAAS;gBACrCC,eAAeE,UAAUL,MAAM,CAACG,aAAa;gBAC7CG,WAAWD,UAAUL,MAAM,CAACM,SAAS;gBACrCL,YAAYI,UAAUJ,UAAU;YAClC;QACF;IACF;IACA,MAAMsB,QAAQzB,QAAQO,UAAUL,MAAM,EAAEiB;IACxC,OAAO;QACLZ;QACAW,OAAOC;QACPK,SAAS;YAAE,GAAGC,KAAK;YAAEtB,YAAYL,gBAAgB2B,MAAMrB,SAAS;QAAE;IACpE;AACF"}
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/replica.ts"],"sourcesContent":["import type { AttachedModelBinding } from './model.js';\nimport { immutable, type ChangeBatch } from './change.js';\nimport {\n parseCollection,\n readCollection,\n validateCollection,\n type Collection,\n} from './collection.js';\nimport { overlay, type Layer } from './overlay.js';\nimport type { ReplicaRecord } from './store.js';\n\nexport type ConfirmedLayer = {\n record: ReplicaRecord;\n collection: Collection;\n};\n\nexport type VisibleLayer = Layer & {\n collection: Collection;\n};\n\nexport type Replica = {\n confirmed: ConfirmedLayer;\n queue: readonly ChangeBatch[];\n visible: VisibleLayer;\n};\n\nexport function readConfirmed(record: ReplicaRecord): ConfirmedLayer | null {\n const collection = readCollection(record.documents, record.collectionRoot, record.model);\n return collection === null ? null : { record, collection };\n}\n\nexport function readStaged(\n record: ReplicaRecord,\n binding: AttachedModelBinding | null,\n): ConfirmedLayer | null {\n if (\n record.model.status === 'current' &&\n binding !== null &&\n validateCollection(\n record.documents,\n record.binaryTargets,\n record.collectionRoot,\n record.model,\n binding,\n ).verdict === 'refuse'\n )\n return null;\n return readConfirmed(record);\n}\n\nexport function applyReturned(\n confirmed: ConfirmedLayer,\n documents: Readonly<Record<string, string>>,\n revisions: Readonly<Record<string, string>>,\n removals: readonly string[],\n roomVersion: string,\n binding: AttachedModelBinding | null,\n): ConfirmedLayer | null {\n const nextDocuments = { ...confirmed.record.documents, ...documents };\n const nextRevisions = { ...confirmed.record.revisions, ...revisions };\n const binaryTargets = new Set(confirmed.record.binaryTargets);\n for (const path of removals) {\n delete nextDocuments[path];\n delete nextRevisions[path];\n binaryTargets.delete(path);\n }\n return readStaged(\n {\n ...confirmed.record,\n roomVersion,\n documents: nextDocuments,\n revisions: nextRevisions,\n binaryTargets: [...binaryTargets].sort(),\n },\n binding,\n );\n}\n\nexport function replicaOf(confirmed: ConfirmedLayer, queue: readonly ChangeBatch[]): Replica {\n const batches = Object.freeze(queue.map(immutable));\n if (batches.length === 0) {\n return {\n confirmed,\n queue: batches,\n visible: {\n documents: confirmed.record.documents,\n binaryTargets: confirmed.record.binaryTargets,\n revisions: confirmed.record.revisions,\n collection: confirmed.collection,\n },\n };\n }\n const layer = overlay(confirmed.record, batches);\n return {\n confirmed,\n queue: batches,\n visible: {\n ...layer,\n collection: parseCollection(layer.documents, confirmed.record.model),\n },\n };\n}\n"],"names":["immutable","parseCollection","readCollection","validateCollection","overlay","readConfirmed","record","collection","documents","collectionRoot","model","readStaged","binding","status","binaryTargets","verdict","applyReturned","confirmed","revisions","removals","roomVersion","nextDocuments","nextRevisions","Set","path","delete","sort","replicaOf","queue","batches","Object","freeze","map","length","visible","layer"],"mappings":"AACA,SAASA,SAAS,QAA0B,cAAc;AAC1D,SACEC,eAAe,EACfC,cAAc,EACdC,kBAAkB,QAEb,kBAAkB;AACzB,SAASC,OAAO,QAAoB,eAAe;AAkBnD,OAAO,SAASC,cAAcC,MAAqB;IACjD,MAAMC,aAAaL,eAAeI,OAAOE,SAAS,EAAEF,OAAOG,cAAc,EAAEH,OAAOI,KAAK;IACvF,OAAOH,eAAe,OAAO,OAAO;QAAED;QAAQC;IAAW;AAC3D;AAEA,OAAO,SAASI,WACdL,MAAqB,EACrBM,OAAoC;IAEpC,IACEN,OAAOI,KAAK,CAACG,MAAM,KAAK,aACxBD,YAAY,QACZT,mBACEG,OAAOE,SAAS,EAChBF,OAAOQ,aAAa,EACpBR,OAAOG,cAAc,EACrBH,OAAOI,KAAK,EACZE,SACAG,OAAO,KAAK,UAEd,OAAO;IACT,OAAOV,cAAcC;AACvB;AAEA,OAAO,SAASU,cACdC,SAAyB,EACzBT,SAA2C,EAC3CU,SAA2C,EAC3CC,QAA2B,EAC3BC,WAAmB,EACnBR,OAAoC;IAEpC,MAAMS,gBAAgB;QAAE,GAAGJ,UAAUX,MAAM,CAACE,SAAS;QAAE,GAAGA,SAAS;IAAC;IACpE,MAAMc,gBAAgB;QAAE,GAAGL,UAAUX,MAAM,CAACY,SAAS;QAAE,GAAGA,SAAS;IAAC;IACpE,MAAMJ,gBAAgB,IAAIS,IAAIN,UAAUX,MAAM,CAACQ,aAAa;IAC5D,KAAK,MAAMU,QAAQL,SAAU;QAC3B,OAAOE,aAAa,CAACG,KAAK;QAC1B,OAAOF,aAAa,CAACE,KAAK;QAC1BV,cAAcW,MAAM,CAACD;IACvB;IACA,OAAOb,WACL;QACE,GAAGM,UAAUX,MAAM;QACnBc;QACAZ,WAAWa;QACXH,WAAWI;QACXR,eAAe;eAAIA;SAAc,CAACY,IAAI;IACxC,GACAd;AAEJ;AAEA,OAAO,SAASe,UAAUV,SAAyB,EAAEW,KAA6B;IAChF,MAAMC,UAAUC,OAAOC,MAAM,CAACH,MAAMI,GAAG,CAAChC;IACxC,IAAI6B,QAAQI,MAAM,KAAK,GAAG;QACxB,OAAO;YACLhB;YACAW,OAAOC;YACPK,SAAS;gBACP1B,WAAWS,UAAUX,MAAM,CAACE,SAAS;gBACrCM,eAAeG,UAAUX,MAAM,CAACQ,aAAa;gBAC7CI,WAAWD,UAAUX,MAAM,CAACY,SAAS;gBACrCX,YAAYU,UAAUV,UAAU;YAClC;QACF;IACF;IACA,MAAM4B,QAAQ/B,QAAQa,UAAUX,MAAM,EAAEuB;IACxC,OAAO;QACLZ;QACAW,OAAOC;QACPK,SAAS;YACP,GAAGC,KAAK;YACR5B,YAAYN,gBAAgBkC,MAAM3B,SAAS,EAAES,UAAUX,MAAM,CAACI,KAAK;QACrE;IACF;AACF"}
package/dist/save.d.ts CHANGED
@@ -1,15 +1,20 @@
1
+ import type { AttachedModelBinding, ModelState } from './model.js';
1
2
  import type { ProviderLimit } from './adapter.js';
2
3
  import { type Change, type ChangeBatch } from './change.js';
3
4
  import type { VisibleLayer } from './replica.js';
4
5
  export type SaveRefusal = {
6
+ source?: 'model';
5
7
  rule: string;
6
8
  file?: string;
7
9
  location?: string;
8
10
  referrers?: readonly string[];
9
11
  };
10
12
  export type SaveInput = {
13
+ collectionRoot: string;
11
14
  baseRoomVersion: string;
12
- writeGrants: readonly string[];
15
+ operations: import('./adapter.js').OperationScopes;
16
+ model: ModelState;
17
+ binding: AttachedModelBinding | null;
13
18
  providerOwnedPaths: readonly string[];
14
19
  providerLimits: readonly ProviderLimit[];
15
20
  visible: VisibleLayer;
@@ -1 +1 @@
1
- {"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,WAAW,EAAqB,MAAM,aAAa,CAAC;AAI1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AA0X9C,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CA2CxD"}
1
+ {"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../src/save.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAa,KAAK,MAAM,EAAE,KAAK,WAAW,EAAqB,MAAM,aAAa,CAAC;AAK1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,OAAO,cAAc,EAAE,eAAe,CAAC;IACnD,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,cAAc,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AA4X9C,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAiGxD"}
package/dist/save.js CHANGED
@@ -1,6 +1,7 @@
1
- import { apply, links, serialize, validate } from '@agentshouse/mdmodel';
1
+ import { apply, links, parse, serialize } from '@agentshouse/mdmodel';
2
2
  import { immutable } from './change.js';
3
- import { parseCollection } from './collection.js';
3
+ import { parseCollection, validateCollection } from './collection.js';
4
+ import { changeBatchIdentity } from './identity.js';
4
5
  import { overlay } from './overlay.js';
5
6
  import { beneath, covered, normalize, relative, resolve } from './paths.js';
6
7
  function refuse(rule, file, location) {
@@ -313,7 +314,8 @@ function guard(changes, input) {
313
314
  if (covered(input.providerOwnedPaths, normalized)) {
314
315
  return refuse('provider-owned-path', normalized);
315
316
  }
316
- if (!covered(input.writeGrants, normalized)) return refuse('write-grant', normalized);
317
+ const operation = change.kind === 'remove' ? 'delete' : 'write';
318
+ if (!covered(input.operations[operation], normalized)) return refuse(`${operation}-grant`, normalized);
317
319
  }
318
320
  if (change.kind === 'create') {
319
321
  if (existing.has(change.path)) return refuse('path-collision', change.path);
@@ -440,6 +442,8 @@ function exceeded(limits, changes, resulting) {
440
442
  return null;
441
443
  }
442
444
  export function buildBatch(input) {
445
+ const structural = input.changes.find((change)=>change.kind === 'move' || change.kind === 'remove');
446
+ if (structural !== undefined && input.model.status === 'unavailable' && Object.values(input.visible.collection.documents).some((document)=>document.type !== undefined && document.type !== 'any')) return refuse('model-unavailable', structural.path);
443
447
  const expanded = expand(input.changes, input.visible);
444
448
  if (expanded.kind === 'refused') return expanded;
445
449
  const rewritten = rewrites(expanded.changes, input.visible);
@@ -459,16 +463,27 @@ export function buildBatch(input) {
459
463
  ]);
460
464
  const removed = new Set(changes.filter((change)=>change.kind === 'remove').map((change)=>change.path));
461
465
  if (removed.size > 0) {
462
- const referenced = incoming(parseCollection(resulting.documents), removed);
466
+ const referenced = incoming(parseCollection(resulting.documents, input.model), removed);
463
467
  if (referenced !== null) return referenced;
464
468
  }
465
- const verdict = validate(resulting.documents, {
466
- binaryTargets: resulting.binaryTargets
467
- });
469
+ const typed = (content)=>{
470
+ if (content === undefined) return false;
471
+ const parsed = parse(content);
472
+ return parsed.ok && parsed.document.type !== undefined && parsed.document.type !== 'any';
473
+ };
474
+ const needsModel = changes.some((change)=>affected(change).some((path)=>typed(input.visible.documents[path]) || typed(resulting.documents[path])));
475
+ if (needsModel && (input.model.status === 'unavailable' || input.binding === null)) {
476
+ return refuse('model-unavailable', changes.find((change)=>affected(change).some((path)=>typed(input.visible.documents[path]) || typed(resulting.documents[path])))?.path);
477
+ }
478
+ const validationText = needsModel ? resulting.documents : Object.fromEntries(Object.entries(resulting.documents).filter(([path])=>changes.some((change)=>affected(change).includes(path))));
479
+ const verdict = validateCollection(validationText, resulting.binaryTargets, input.collectionRoot, input.model, input.binding);
468
480
  if (verdict.verdict === 'refuse') {
469
481
  return {
470
482
  kind: 'refused',
471
483
  refusal: {
484
+ ...verdict.source === 'model' ? {
485
+ source: 'model'
486
+ } : {},
472
487
  rule: verdict.rule,
473
488
  file: verdict.file,
474
489
  ...verdict.location === undefined ? {} : {
@@ -485,10 +500,17 @@ export function buildBatch(input) {
485
500
  return {
486
501
  kind: 'batch',
487
502
  batch: immutable({
488
- id: crypto.randomUUID(),
503
+ id: changeBatchIdentity(),
489
504
  baseRoomVersion: input.baseRoomVersion,
490
505
  changes,
491
- preconditions
506
+ preconditions,
507
+ ...needsModel && input.model.status !== 'unavailable' ? {
508
+ validation: {
509
+ identity: input.model.snapshot.identity,
510
+ version: input.model.snapshot.version,
511
+ source: input.model.status
512
+ }
513
+ } : {}
492
514
  })
493
515
  };
494
516
  }