@objectstack/metadata-core 5.0.0

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.
@@ -0,0 +1,254 @@
1
+ import {
2
+ ConflictError,
3
+ hashSpec
4
+ } from "./chunk-G3VZZW54.js";
5
+
6
+ // src/contract-suite.ts
7
+ import { describe, it, expect } from "vitest";
8
+ var refOf = (overrides = {}) => ({
9
+ org: "system",
10
+ type: "view",
11
+ name: "sample_view",
12
+ ...overrides
13
+ });
14
+ var spec = (label) => ({ label, columns: ["a", "b"] });
15
+ async function take(iter, n, timeoutMs = 1e3) {
16
+ const out = [];
17
+ const it2 = iter[Symbol.asyncIterator]();
18
+ const deadline = Date.now() + timeoutMs;
19
+ while (out.length < n) {
20
+ const remaining = deadline - Date.now();
21
+ if (remaining <= 0) break;
22
+ const result = await Promise.race([
23
+ it2.next(),
24
+ new Promise(
25
+ (resolve) => setTimeout(() => resolve({ value: void 0, done: true }), remaining)
26
+ )
27
+ ]);
28
+ if (result.done) break;
29
+ out.push(result.value);
30
+ }
31
+ await it2.return?.(void 0);
32
+ return out;
33
+ }
34
+ function runRepositoryContractTests(label, factory, opts = {}) {
35
+ describe(`MetadataRepository contract \u2014 ${label}`, () => {
36
+ describe("put / get", () => {
37
+ it("creates an item from null parent", async () => {
38
+ const repo = await factory();
39
+ const ref = refOf();
40
+ const res = await repo.put(ref, spec("hello"), { parentVersion: null, actor: "tester" });
41
+ expect(res.version).toMatch(/^sha256:[0-9a-f]{64}$/);
42
+ expect(res.version).toBe(hashSpec(spec("hello")));
43
+ expect(res.seq).toBeGreaterThan(0);
44
+ expect(res.item.parentHash).toBeNull();
45
+ expect(res.item.authoredBy).toBe("tester");
46
+ const got = await repo.get(ref);
47
+ expect(got).not.toBeNull();
48
+ expect(got.hash).toBe(res.version);
49
+ expect(got.body).toEqual(spec("hello"));
50
+ });
51
+ it("round-trips successive updates with parent chaining", async () => {
52
+ const repo = await factory();
53
+ const ref = refOf();
54
+ const a = await repo.put(ref, spec("one"), { parentVersion: null, actor: "t" });
55
+ const b = await repo.put(ref, spec("two"), { parentVersion: a.version, actor: "t" });
56
+ const c = await repo.put(ref, spec("three"), { parentVersion: b.version, actor: "t" });
57
+ expect(b.item.parentHash).toBe(a.version);
58
+ expect(c.item.parentHash).toBe(b.version);
59
+ expect(c.seq).toBeGreaterThan(b.seq);
60
+ expect(b.seq).toBeGreaterThan(a.seq);
61
+ });
62
+ it("canonical hash invariant: item.hash === hashSpec(item.body)", async () => {
63
+ const repo = await factory();
64
+ const ref = refOf();
65
+ await repo.put(ref, { z: 1, a: 2, m: [3, 1, 2] }, { parentVersion: null, actor: "t" });
66
+ const got = await repo.get(ref);
67
+ expect(got.hash).toBe(hashSpec(got.body));
68
+ });
69
+ it("returns null for missing item", async () => {
70
+ const repo = await factory();
71
+ expect(await repo.get(refOf({ name: "never_existed" }))).toBeNull();
72
+ });
73
+ it("no-op write with identical content returns current version", async () => {
74
+ const repo = await factory();
75
+ const ref = refOf();
76
+ const a = await repo.put(ref, spec("same"), { parentVersion: null, actor: "t" });
77
+ const b = await repo.put(ref, spec("same"), { parentVersion: a.version, actor: "t" });
78
+ expect(b.version).toBe(a.version);
79
+ expect(b.seq).toBe(a.seq);
80
+ });
81
+ });
82
+ describe("optimistic locking", () => {
83
+ it("throws ConflictError when parentVersion mismatches", async () => {
84
+ const repo = await factory();
85
+ const ref = refOf();
86
+ const a = await repo.put(ref, spec("v1"), { parentVersion: null, actor: "t" });
87
+ await expect(
88
+ repo.put(ref, spec("v2"), { parentVersion: null, actor: "t" })
89
+ ).rejects.toBeInstanceOf(ConflictError);
90
+ await expect(
91
+ repo.put(ref, spec("v2"), { parentVersion: "sha256:deadbeef".padEnd(71, "0"), actor: "t" })
92
+ ).rejects.toBeInstanceOf(ConflictError);
93
+ await expect(
94
+ repo.put(ref, spec("v2"), { parentVersion: a.version, actor: "t" })
95
+ ).resolves.toMatchObject({ seq: expect.any(Number) });
96
+ });
97
+ it("throws ConflictError when creating over an existing item with null parent", async () => {
98
+ const repo = await factory();
99
+ const ref = refOf();
100
+ await repo.put(ref, spec("a"), { parentVersion: null, actor: "t" });
101
+ await expect(
102
+ repo.put(ref, spec("b"), { parentVersion: null, actor: "t" })
103
+ ).rejects.toBeInstanceOf(ConflictError);
104
+ });
105
+ it("delete requires correct parentVersion", async () => {
106
+ const repo = await factory();
107
+ const ref = refOf();
108
+ const a = await repo.put(ref, spec("a"), { parentVersion: null, actor: "t" });
109
+ await expect(
110
+ repo.delete(ref, { parentVersion: "sha256:wrong".padEnd(71, "0"), actor: "t" })
111
+ ).rejects.toBeInstanceOf(ConflictError);
112
+ await repo.delete(ref, { parentVersion: a.version, actor: "t" });
113
+ });
114
+ });
115
+ describe("monotonic seq per org", () => {
116
+ it("seq strictly increases within an org", async () => {
117
+ const repo = await factory();
118
+ const ref = refOf();
119
+ const a = await repo.put(ref, spec("1"), { parentVersion: null, actor: "t" });
120
+ const b = await repo.put(ref, spec("2"), { parentVersion: a.version, actor: "t" });
121
+ const c = await repo.put(refOf({ name: "other" }), spec("o"), { parentVersion: null, actor: "t" });
122
+ expect(b.seq).toBeGreaterThan(a.seq);
123
+ expect(c.seq).toBeGreaterThan(b.seq);
124
+ });
125
+ it("different orgs have independent sequences", async () => {
126
+ const repo = await factory();
127
+ const orgA = refOf({ org: "org_a" });
128
+ const orgB = refOf({ org: "org_b" });
129
+ let a;
130
+ let b;
131
+ try {
132
+ a = await repo.put(orgA, spec("a1"), { parentVersion: null, actor: "t" });
133
+ b = await repo.put(orgB, spec("b1"), { parentVersion: null, actor: "t" });
134
+ } catch {
135
+ return;
136
+ }
137
+ const c = await repo.put(orgA, spec("a2"), { parentVersion: a.version, actor: "t" });
138
+ const d = await repo.put(orgB, spec("b2"), { parentVersion: b.version, actor: "t" });
139
+ expect(c.seq).toBeGreaterThan(a.seq);
140
+ expect(d.seq).toBeGreaterThan(b.seq);
141
+ });
142
+ });
143
+ describe("delete / tombstones", () => {
144
+ it("get returns null after delete; history retains lineage", async () => {
145
+ const repo = await factory();
146
+ const ref = refOf();
147
+ const a = await repo.put(ref, spec("a"), { parentVersion: null, actor: "t" });
148
+ await repo.delete(ref, { parentVersion: a.version, actor: "t" });
149
+ expect(await repo.get(ref)).toBeNull();
150
+ const hist = [];
151
+ for await (const evt of repo.history(ref)) hist.push(evt);
152
+ expect(hist.map((e) => e.op)).toEqual(["create", "delete"]);
153
+ expect(hist[1]?.parentHash).toBe(a.version);
154
+ expect(hist[1]?.hash).toBeNull();
155
+ });
156
+ it("can recreate after delete with null parent", async () => {
157
+ const repo = await factory();
158
+ const ref = refOf();
159
+ const a = await repo.put(ref, spec("a"), { parentVersion: null, actor: "t" });
160
+ await repo.delete(ref, { parentVersion: a.version, actor: "t" });
161
+ const b = await repo.put(ref, spec("a-redux"), { parentVersion: null, actor: "t" });
162
+ expect(b.item.parentHash).toBeNull();
163
+ });
164
+ });
165
+ describe("watch / history", () => {
166
+ it("history yields events in monotonic seq order", async () => {
167
+ const repo = await factory();
168
+ const ref = refOf();
169
+ const a = await repo.put(ref, spec("1"), { parentVersion: null, actor: "t" });
170
+ const b = await repo.put(ref, spec("2"), { parentVersion: a.version, actor: "t" });
171
+ const c = await repo.put(ref, spec("3"), { parentVersion: b.version, actor: "t" });
172
+ const evts = [];
173
+ for await (const e of repo.history(ref)) evts.push(e);
174
+ expect(evts.map((e) => e.seq)).toEqual([a.seq, b.seq, c.seq]);
175
+ expect(evts.every((e, i) => i === 0 || e.seq > evts[i - 1].seq)).toBe(true);
176
+ });
177
+ it("watch(sinceSeq) replays subsequent events then goes live", async () => {
178
+ const repo = await factory();
179
+ const ref = refOf();
180
+ const a = await repo.put(ref, spec("1"), { parentVersion: null, actor: "t" });
181
+ const b = await repo.put(ref, spec("2"), { parentVersion: a.version, actor: "t" });
182
+ const iter = repo.watch({ org: ref.org }, a.seq);
183
+ const collected = [];
184
+ const it2 = iter[Symbol.asyncIterator]();
185
+ const first = await it2.next();
186
+ expect(first.done).toBe(false);
187
+ collected.push(first.value);
188
+ expect(collected[0].seq).toBe(b.seq);
189
+ const livePromise = it2.next();
190
+ const c = await repo.put(ref, spec("3"), { parentVersion: b.version, actor: "t" });
191
+ const live = await livePromise;
192
+ expect(live.done).toBe(false);
193
+ collected.push(live.value);
194
+ expect(collected[1].seq).toBe(c.seq);
195
+ await it2.return?.(void 0);
196
+ });
197
+ it("watch filters by type and name", async () => {
198
+ const repo = await factory();
199
+ await repo.put(refOf({ name: "a" }), spec("a"), { parentVersion: null, actor: "t" });
200
+ await repo.put(refOf({ name: "b" }), spec("b"), { parentVersion: null, actor: "t" });
201
+ const events = await take(
202
+ repo.watch({ org: "system", type: "view", name: "a" }),
203
+ 5,
204
+ 200
205
+ );
206
+ expect(events.length).toBe(1);
207
+ expect(events[0].ref.name).toBe("a");
208
+ });
209
+ });
210
+ describe("list", () => {
211
+ it("returns headers (no body) for matching items", async () => {
212
+ const repo = await factory();
213
+ await repo.put(refOf({ name: "alpha" }), spec("a"), { parentVersion: null, actor: "t" });
214
+ await repo.put(refOf({ name: "beta" }), spec("b"), { parentVersion: null, actor: "t" });
215
+ await repo.put(refOf({ type: "object", name: "thing" }), spec("o"), {
216
+ parentVersion: null,
217
+ actor: "t"
218
+ });
219
+ const headers = [];
220
+ for await (const h of repo.list({ type: "view" })) headers.push(h);
221
+ expect(headers.length).toBe(2);
222
+ for (const h of headers) {
223
+ expect(h.body).toBeUndefined();
224
+ }
225
+ });
226
+ it("limit clamps result size", async () => {
227
+ const repo = await factory();
228
+ for (let i = 0; i < 5; i++) {
229
+ await repo.put(refOf({ name: `v_${i}` }), spec(`v${i}`), { parentVersion: null, actor: "t" });
230
+ }
231
+ const headers = [];
232
+ for await (const h of repo.list({ type: "view", limit: 3 })) headers.push(h);
233
+ expect(headers.length).toBe(3);
234
+ });
235
+ });
236
+ if (opts.supportsVersionedReads) {
237
+ describe("versioned reads", () => {
238
+ it("get with version pin returns that historical version", async () => {
239
+ const repo = await factory();
240
+ const ref = refOf();
241
+ const a = await repo.put(ref, spec("v1"), { parentVersion: null, actor: "t" });
242
+ await repo.put(ref, spec("v2"), { parentVersion: a.version, actor: "t" });
243
+ const pinned = await repo.get({ ...ref, version: a.version });
244
+ expect(pinned?.hash).toBe(a.version);
245
+ expect(pinned?.body).toEqual(spec("v1"));
246
+ });
247
+ });
248
+ }
249
+ });
250
+ }
251
+ export {
252
+ runRepositoryContractTests
253
+ };
254
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/contract-suite.ts"],"sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\n/**\n * Parameterised Repository contract test suite. Every `MetadataRepository`\n * implementation MUST pass this suite. Reuse:\n *\n * import { runRepositoryContractTests } from '@objectstack/metadata-core/test';\n * runRepositoryContractTests('InMemory', () => new InMemoryRepository());\n *\n * The suite verifies the seven invariants from `repository.ts`:\n *\n * 1. Atomic put\n * 2. Monotonic seq per branch\n * 3. Optimistic locking (ConflictError)\n * 4. Canonical hashing (hash === hashSpec(body))\n * 5. Event ordering (monotonic seq, no gaps)\n * 6. Resumability (watch with `since` replays)\n * 7. Tombstones (delete event emitted, get returns null)\n */\n\nimport { describe, it, expect } from 'vitest';\nimport type { MetadataRepository } from './repository.js';\nimport type { MetaRef, MetadataEvent } from './types.js';\nimport { hashSpec } from './canonicalize.js';\nimport { ConflictError } from './errors.js';\n\nexport interface ContractSuiteOptions {\n /** If the implementation supports `version`-pinned reads, set true. */\n supportsVersionedReads?: boolean;\n}\n\nconst refOf = (overrides: Partial<MetaRef> = {}): MetaRef => ({\n org: 'system',\n type: 'view',\n name: 'sample_view',\n ...overrides,\n});\n\nconst spec = (label: string) => ({ label, columns: ['a', 'b'] });\n\n/** Drain at most `n` events from an async iterable with a timeout. */\nasync function take<T>(iter: AsyncIterable<T>, n: number, timeoutMs = 1000): Promise<T[]> {\n const out: T[] = [];\n const it = iter[Symbol.asyncIterator]();\n const deadline = Date.now() + timeoutMs;\n while (out.length < n) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n const result = await Promise.race([\n it.next(),\n new Promise<{ value: undefined; done: true }>((resolve) =>\n setTimeout(() => resolve({ value: undefined, done: true }), remaining),\n ),\n ]);\n if (result.done) break;\n out.push(result.value as T);\n }\n // Close the iterator so the repo subscriber is freed.\n await it.return?.(undefined);\n return out;\n}\n\nexport function runRepositoryContractTests(\n label: string,\n factory: () => MetadataRepository | Promise<MetadataRepository>,\n opts: ContractSuiteOptions = {},\n): void {\n describe(`MetadataRepository contract — ${label}`, () => {\n // ── 1. Atomic put + canonical hash ──────────────────────────────\n describe('put / get', () => {\n it('creates an item from null parent', async () => {\n const repo = await factory();\n const ref = refOf();\n const res = await repo.put(ref, spec('hello'), { parentVersion: null, actor: 'tester' });\n expect(res.version).toMatch(/^sha256:[0-9a-f]{64}$/);\n expect(res.version).toBe(hashSpec(spec('hello')));\n expect(res.seq).toBeGreaterThan(0);\n expect(res.item.parentHash).toBeNull();\n expect(res.item.authoredBy).toBe('tester');\n\n const got = await repo.get(ref);\n expect(got).not.toBeNull();\n expect(got!.hash).toBe(res.version);\n expect(got!.body).toEqual(spec('hello'));\n });\n\n it('round-trips successive updates with parent chaining', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('one'), { parentVersion: null, actor: 't' });\n const b = await repo.put(ref, spec('two'), { parentVersion: a.version, actor: 't' });\n const c = await repo.put(ref, spec('three'), { parentVersion: b.version, actor: 't' });\n expect(b.item.parentHash).toBe(a.version);\n expect(c.item.parentHash).toBe(b.version);\n expect(c.seq).toBeGreaterThan(b.seq);\n expect(b.seq).toBeGreaterThan(a.seq);\n });\n\n it('canonical hash invariant: item.hash === hashSpec(item.body)', async () => {\n const repo = await factory();\n const ref = refOf();\n await repo.put(ref, { z: 1, a: 2, m: [3, 1, 2] }, { parentVersion: null, actor: 't' });\n const got = await repo.get(ref);\n expect(got!.hash).toBe(hashSpec(got!.body));\n });\n\n it('returns null for missing item', async () => {\n const repo = await factory();\n expect(await repo.get(refOf({ name: 'never_existed' }))).toBeNull();\n });\n\n it('no-op write with identical content returns current version', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('same'), { parentVersion: null, actor: 't' });\n const b = await repo.put(ref, spec('same'), { parentVersion: a.version, actor: 't' });\n expect(b.version).toBe(a.version);\n expect(b.seq).toBe(a.seq);\n });\n });\n\n // ── 2 & 3. Optimistic locking + Monotonic seq ───────────────────\n describe('optimistic locking', () => {\n it('throws ConflictError when parentVersion mismatches', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('v1'), { parentVersion: null, actor: 't' });\n await expect(\n repo.put(ref, spec('v2'), { parentVersion: null, actor: 't' }),\n ).rejects.toBeInstanceOf(ConflictError);\n await expect(\n repo.put(ref, spec('v2'), { parentVersion: 'sha256:deadbeef'.padEnd(71, '0'), actor: 't' }),\n ).rejects.toBeInstanceOf(ConflictError);\n // Sanity: correct parent succeeds.\n await expect(\n repo.put(ref, spec('v2'), { parentVersion: a.version, actor: 't' }),\n ).resolves.toMatchObject({ seq: expect.any(Number) });\n });\n\n it('throws ConflictError when creating over an existing item with null parent', async () => {\n const repo = await factory();\n const ref = refOf();\n await repo.put(ref, spec('a'), { parentVersion: null, actor: 't' });\n await expect(\n repo.put(ref, spec('b'), { parentVersion: null, actor: 't' }),\n ).rejects.toBeInstanceOf(ConflictError);\n });\n\n it('delete requires correct parentVersion', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('a'), { parentVersion: null, actor: 't' });\n await expect(\n repo.delete(ref, { parentVersion: 'sha256:wrong'.padEnd(71, '0'), actor: 't' }),\n ).rejects.toBeInstanceOf(ConflictError);\n await repo.delete(ref, { parentVersion: a.version, actor: 't' });\n });\n });\n\n describe('monotonic seq per org', () => {\n it('seq strictly increases within an org', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('1'), { parentVersion: null, actor: 't' });\n const b = await repo.put(ref, spec('2'), { parentVersion: a.version, actor: 't' });\n const c = await repo.put(refOf({ name: 'other' }), spec('o'), { parentVersion: null, actor: 't' });\n expect(b.seq).toBeGreaterThan(a.seq);\n expect(c.seq).toBeGreaterThan(b.seq);\n });\n\n it('different orgs have independent sequences', async () => {\n const repo = await factory();\n const orgA = refOf({ org: 'org_a' });\n const orgB = refOf({ org: 'org_b' });\n // Some backends (FileSystemRepository) are scoped to a single\n // org; for those any foreign-org put throws — skip the test.\n let a: { seq: number; version: string };\n let b: { seq: number; version: string };\n try {\n a = await repo.put(orgA, spec('a1'), { parentVersion: null, actor: 't' });\n b = await repo.put(orgB, spec('b1'), { parentVersion: null, actor: 't' });\n } catch {\n return;\n }\n const c = await repo.put(orgA, spec('a2'), { parentVersion: a.version, actor: 't' });\n const d = await repo.put(orgB, spec('b2'), { parentVersion: b.version, actor: 't' });\n expect(c.seq).toBeGreaterThan(a.seq);\n expect(d.seq).toBeGreaterThan(b.seq);\n });\n });\n\n // ── 4. Tombstones ───────────────────────────────────────────────\n describe('delete / tombstones', () => {\n it('get returns null after delete; history retains lineage', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('a'), { parentVersion: null, actor: 't' });\n await repo.delete(ref, { parentVersion: a.version, actor: 't' });\n expect(await repo.get(ref)).toBeNull();\n const hist: MetadataEvent[] = [];\n for await (const evt of repo.history(ref)) hist.push(evt);\n expect(hist.map((e) => e.op)).toEqual(['create', 'delete']);\n expect(hist[1]?.parentHash).toBe(a.version);\n expect(hist[1]?.hash).toBeNull();\n });\n\n it('can recreate after delete with null parent', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('a'), { parentVersion: null, actor: 't' });\n await repo.delete(ref, { parentVersion: a.version, actor: 't' });\n const b = await repo.put(ref, spec('a-redux'), { parentVersion: null, actor: 't' });\n expect(b.item.parentHash).toBeNull();\n });\n });\n\n // ── 5. Event ordering & watch replay ────────────────────────────\n describe('watch / history', () => {\n it('history yields events in monotonic seq order', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('1'), { parentVersion: null, actor: 't' });\n const b = await repo.put(ref, spec('2'), { parentVersion: a.version, actor: 't' });\n const c = await repo.put(ref, spec('3'), { parentVersion: b.version, actor: 't' });\n const evts: MetadataEvent[] = [];\n for await (const e of repo.history(ref)) evts.push(e);\n expect(evts.map((e) => e.seq)).toEqual([a.seq, b.seq, c.seq]);\n expect(evts.every((e, i) => i === 0 || e.seq > evts[i - 1]!.seq)).toBe(true);\n });\n\n it('watch(sinceSeq) replays subsequent events then goes live', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('1'), { parentVersion: null, actor: 't' });\n const b = await repo.put(ref, spec('2'), { parentVersion: a.version, actor: 't' });\n\n // Start watching with `since = a.seq` — must replay b, then deliver a live event.\n const iter = repo.watch({ org: ref.org }, a.seq);\n const collected: MetadataEvent[] = [];\n const it = iter[Symbol.asyncIterator]();\n\n // First yield should be the replay of `b`.\n const first = await it.next();\n expect(first.done).toBe(false);\n collected.push(first.value as MetadataEvent);\n expect(collected[0]!.seq).toBe(b.seq);\n\n // Now trigger a live event and collect it.\n const livePromise = it.next();\n const c = await repo.put(ref, spec('3'), { parentVersion: b.version, actor: 't' });\n const live = await livePromise;\n expect(live.done).toBe(false);\n collected.push(live.value as MetadataEvent);\n expect(collected[1]!.seq).toBe(c.seq);\n\n await it.return?.(undefined);\n });\n\n it('watch filters by type and name', async () => {\n const repo = await factory();\n await repo.put(refOf({ name: 'a' }), spec('a'), { parentVersion: null, actor: 't' });\n await repo.put(refOf({ name: 'b' }), spec('b'), { parentVersion: null, actor: 't' });\n const events = await take(\n repo.watch({ org: 'system', type: 'view', name: 'a' }),\n 5,\n 200,\n );\n expect(events.length).toBe(1);\n expect(events[0]!.ref.name).toBe('a');\n });\n });\n\n // ── list ────────────────────────────────────────────────────────\n describe('list', () => {\n it('returns headers (no body) for matching items', async () => {\n const repo = await factory();\n await repo.put(refOf({ name: 'alpha' }), spec('a'), { parentVersion: null, actor: 't' });\n await repo.put(refOf({ name: 'beta' }), spec('b'), { parentVersion: null, actor: 't' });\n await repo.put(refOf({ type: 'object', name: 'thing' }), spec('o'), {\n parentVersion: null,\n actor: 't',\n });\n const headers: unknown[] = [];\n for await (const h of repo.list({ type: 'view' })) headers.push(h);\n expect(headers.length).toBe(2);\n for (const h of headers) {\n expect((h as { body?: unknown }).body).toBeUndefined();\n }\n });\n\n it('limit clamps result size', async () => {\n const repo = await factory();\n for (let i = 0; i < 5; i++) {\n await repo.put(refOf({ name: `v_${i}` }), spec(`v${i}`), { parentVersion: null, actor: 't' });\n }\n const headers: unknown[] = [];\n for await (const h of repo.list({ type: 'view', limit: 3 })) headers.push(h);\n expect(headers.length).toBe(3);\n });\n });\n\n // ── Optional behaviour ──────────────────────────────────────────\n if (opts.supportsVersionedReads) {\n describe('versioned reads', () => {\n it('get with version pin returns that historical version', async () => {\n const repo = await factory();\n const ref = refOf();\n const a = await repo.put(ref, spec('v1'), { parentVersion: null, actor: 't' });\n await repo.put(ref, spec('v2'), { parentVersion: a.version, actor: 't' });\n const pinned = await repo.get({ ...ref, version: a.version });\n expect(pinned?.hash).toBe(a.version);\n expect(pinned?.body).toEqual(spec('v1'));\n });\n });\n }\n });\n}\n"],"mappings":"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","names":["it"]}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@objectstack/metadata-core",
3
+ "version": "5.0.0",
4
+ "license": "Apache-2.0",
5
+ "description": "Metadata Repository contracts: types, canonicalization, errors, interface (ADR-0008).",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ },
15
+ "./testing": {
16
+ "types": "./dist/testing.d.ts",
17
+ "import": "./dist/testing.js",
18
+ "require": "./dist/testing.cjs"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "keywords": [
26
+ "objectstack",
27
+ "metadata",
28
+ "repository",
29
+ "change-log"
30
+ ],
31
+ "dependencies": {
32
+ "zod": "^4.4.3"
33
+ },
34
+ "peerDependencies": {
35
+ "vitest": "^4.0.0"
36
+ },
37
+ "peerDependenciesMeta": {
38
+ "vitest": {
39
+ "optional": true
40
+ }
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^25.9.1",
44
+ "fast-check": "^4.8.0",
45
+ "tsup": "^8.5.1",
46
+ "typescript": "^6.0.3",
47
+ "vitest": "^4.1.7"
48
+ },
49
+ "author": "ObjectStack",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/objectstack-ai/framework.git",
53
+ "directory": "packages/metadata-core"
54
+ },
55
+ "homepage": "https://objectstack.ai/docs",
56
+ "bugs": "https://github.com/objectstack-ai/framework/issues",
57
+ "publishConfig": {
58
+ "access": "public"
59
+ },
60
+ "engines": {
61
+ "node": ">=18.0.0"
62
+ },
63
+ "scripts": {
64
+ "build": "tsup",
65
+ "dev": "tsc --watch",
66
+ "clean": "rm -rf dist",
67
+ "test": "vitest run",
68
+ "test:watch": "vitest"
69
+ }
70
+ }