@spfn/core 0.3.0-beta.18 → 0.3.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codegen/index.d.ts +20 -0
- package/dist/codegen/index.js +68 -10
- package/dist/codegen/index.js.map +1 -1
- package/dist/contract/index.d.ts +37 -15
- package/dist/contract/index.js +147 -23
- package/dist/contract/index.js.map +1 -1
- package/dist/event/index.d.ts +4 -3
- package/dist/event/index.js +32 -1
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +3 -2
- package/dist/event/sse/index.d.ts +5 -4
- package/dist/event/ws/client.d.ts +3 -2
- package/dist/event/ws/index.d.ts +4 -3
- package/dist/ops/index.d.ts +1 -1
- package/dist/{token-manager-BT5EnUAR.d.ts → router-CysBmgv3.d.ts} +81 -127
- package/dist/server/index.d.ts +4 -3
- package/dist/server/index.js +26 -2
- package/dist/server/index.js.map +1 -1
- package/dist/token-manager-Ckjt2-qq.d.ts +122 -0
- package/dist/{types-ClQVomgV.d.ts → types-B4DuGCyM.d.ts} +42 -3
- package/dist/{types-ZQODsBft.d.ts → types-B8zAxFsE.d.ts} +2 -1
- package/dist/{types-2AbaW4Ie.d.ts → types-W4u_S0lF.d.ts} +4 -3
- package/package.json +1 -1
- package/src/codegen/README.md +11 -2
- package/src/contract/README.md +113 -5
- package/src/event/README.md +48 -0
package/dist/contract/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { E as EventRouterDef } from '../router-CysBmgv3.js';
|
|
1
2
|
import { R as Router } from '../router-BqyEARoY.js';
|
|
2
|
-
import { C as ContractDocument, a as ContractViolation, b as ContractOperation, c as ContractSnapshot } from '../types-
|
|
3
|
-
export { d as CompatibilityPolicy, e as
|
|
3
|
+
import { C as ContractDocument, a as ContractViolation, b as ContractOperation, c as ContractSnapshot } from '../types-B4DuGCyM.js';
|
|
4
|
+
export { d as CompatibilityPolicy, e as ContractEvent, f as ContractEvents, g as ContractRequest, h as ContractViolationKind, J as JsonSchema } from '../types-B4DuGCyM.js';
|
|
5
|
+
import '@sinclair/typebox';
|
|
4
6
|
import '../define-middleware-CVKgqo8S.js';
|
|
5
7
|
import 'hono';
|
|
6
8
|
import '../route-builder-2ani2jEI.js';
|
|
7
|
-
import '@sinclair/typebox';
|
|
8
9
|
import 'hono/utils/http-status';
|
|
9
10
|
import '../route/types.js';
|
|
10
11
|
|
|
@@ -12,7 +13,8 @@ import '../route/types.js';
|
|
|
12
13
|
* Contract Collection
|
|
13
14
|
*
|
|
14
15
|
* Walks a loaded router and turns every route carrying `.contract()` into a
|
|
15
|
-
* contract operation
|
|
16
|
+
* contract operation, and every event of an event router carrying
|
|
17
|
+
* `.contract()` into a contract event.
|
|
16
18
|
*
|
|
17
19
|
* The router is loaded and walked rather than parsed from source. Real routes
|
|
18
20
|
* build their schemas from imported values — `EmailSchema`, `FileSchema()`,
|
|
@@ -26,11 +28,14 @@ declare class ContractCollectionError extends Error {
|
|
|
26
28
|
constructor(message: string);
|
|
27
29
|
}
|
|
28
30
|
/**
|
|
29
|
-
* Build the contract document from a loaded router
|
|
31
|
+
* Build the contract document from a loaded router and, optionally, the app's
|
|
32
|
+
* event router.
|
|
30
33
|
*
|
|
31
|
-
* Routes without `.contract()` are skipped — they are not part of
|
|
34
|
+
* Routes and events without `.contract()` are skipped — they are not part of
|
|
35
|
+
* the promise. A document with no contracted event carries no `events` key, so
|
|
36
|
+
* it is byte-identical to one collected without an event router.
|
|
32
37
|
*/
|
|
33
|
-
declare function collectContractDocument(router: Router<any>): ContractDocument;
|
|
38
|
+
declare function collectContractDocument(router: Router<any>, eventRouter?: EventRouterDef<any>): ContractDocument;
|
|
34
39
|
|
|
35
40
|
/**
|
|
36
41
|
* Backward-compatibility comparison
|
|
@@ -52,6 +57,10 @@ declare function collectContractDocument(router: Router<any>): ContractDocument;
|
|
|
52
57
|
* | required → optional | pass | refuse |
|
|
53
58
|
* | optional → required | refuse | pass |
|
|
54
59
|
* | type changed | refuse | refuse |
|
|
60
|
+
*
|
|
61
|
+
* An event payload flows server → client like a response, so it is compared
|
|
62
|
+
* under the response rules by the same walk, and only the violation kinds are
|
|
63
|
+
* renamed.
|
|
55
64
|
*/
|
|
56
65
|
|
|
57
66
|
interface DocumentComparison {
|
|
@@ -63,14 +72,19 @@ interface DocumentComparison {
|
|
|
63
72
|
* whether any released app still calls it, which is a separate check.
|
|
64
73
|
*/
|
|
65
74
|
removedOperations: string[];
|
|
75
|
+
/**
|
|
76
|
+
* Events present in the baseline and gone from the current contract —
|
|
77
|
+
* decided against usage files exactly as a removed operation is.
|
|
78
|
+
*/
|
|
79
|
+
removedEvents: string[];
|
|
66
80
|
}
|
|
67
81
|
/** Compare one operation that exists on both sides. */
|
|
68
82
|
declare function compareOperation(before: ContractOperation, after: ContractOperation): ContractViolation[];
|
|
69
83
|
/**
|
|
70
84
|
* Compare a released contract against the one this build produced.
|
|
71
85
|
*
|
|
72
|
-
* Operations that are new in `after` need no check — nothing has
|
|
73
|
-
* about them yet.
|
|
86
|
+
* Operations and events that are new in `after` need no check — nothing has
|
|
87
|
+
* been promised about them yet.
|
|
74
88
|
*/
|
|
75
89
|
declare function compareDocuments(before: ContractDocument, after: ContractDocument): DocumentComparison;
|
|
76
90
|
|
|
@@ -79,7 +93,7 @@ declare function compareDocuments(before: ContractDocument, after: ContractDocum
|
|
|
79
93
|
*
|
|
80
94
|
* Puts the pieces together: read the newest released snapshot, compare this
|
|
81
95
|
* build's contract against it, and decide removals against what released
|
|
82
|
-
* clients still call.
|
|
96
|
+
* clients still call or subscribe to.
|
|
83
97
|
*
|
|
84
98
|
* Nothing released yet is a pass — with a warning. "This is the first contract"
|
|
85
99
|
* and "the release that should have written a snapshot didn't" produce the same
|
|
@@ -181,12 +195,12 @@ declare function readCurrentDocument(contractsDir: string): ContractDocument;
|
|
|
181
195
|
declare function writeCurrentDocument(contractsDir: string, document: ContractDocument): boolean;
|
|
182
196
|
|
|
183
197
|
/**
|
|
184
|
-
* Usage files — who still calls an operation
|
|
198
|
+
* Usage files — who still calls an operation or subscribes to an event
|
|
185
199
|
*
|
|
186
200
|
* A released app is compiled and shipped; the server cannot ask it what it
|
|
187
|
-
* calls. So each released client writes down the operations it uses
|
|
188
|
-
* files are what a removal is judged
|
|
189
|
-
* `contracts/usage/<platform>-<appVersion>.json`.
|
|
201
|
+
* calls. So each released client writes down the operations it uses and the
|
|
202
|
+
* events it subscribes to, and those files are what a removal is judged
|
|
203
|
+
* against: `contracts/usage/<platform>-<appVersion>.json`.
|
|
190
204
|
*
|
|
191
205
|
* The one rule this file exists to hold: **an unreadable file and "nobody calls
|
|
192
206
|
* it" are not the same answer.** An empty scan result reading as a pass is how
|
|
@@ -198,6 +212,12 @@ interface UsageRecord {
|
|
|
198
212
|
platform: string;
|
|
199
213
|
appVersion: string;
|
|
200
214
|
operations: string[];
|
|
215
|
+
/**
|
|
216
|
+
* Contracted events the client subscribes to. Always set when read from a
|
|
217
|
+
* file — a file without the key subscribes to none — and optional only so a
|
|
218
|
+
* record built by hand before events were contracted still type-checks.
|
|
219
|
+
*/
|
|
220
|
+
events?: string[];
|
|
201
221
|
/** File this came from, for messages. */
|
|
202
222
|
file: string;
|
|
203
223
|
}
|
|
@@ -217,5 +237,7 @@ type UsageReadResult = {
|
|
|
217
237
|
declare function readUsageRecords(usageDir: string): UsageReadResult;
|
|
218
238
|
/** Which released clients still call `operation`. */
|
|
219
239
|
declare function callersOf(operation: string, records: UsageRecord[]): UsageRecord[];
|
|
240
|
+
/** Which released clients still subscribe to `event`. */
|
|
241
|
+
declare function subscribersOf(event: string, records: UsageRecord[]): UsageRecord[];
|
|
220
242
|
|
|
221
|
-
export { CURRENT_FILENAME, type ContractCheckResult, ContractCollectionError, ContractDocument, ContractOperation, ContractSnapshot, ContractSnapshotError, ContractViolation, type DocumentComparison, RELEASED_DIRNAME, type SnapshotFile, USAGE_DIRNAME, type UsageReadResult, type UsageRecord, callersOf, canonicalize, checkContract, collectContractDocument, compareDocuments, compareOperation, compareVersions, currentPath, formatViolations, listSnapshots, newestSnapshot, readCurrentDocument, readSnapshot, readUsageRecords, releasedDir, stableDigest, stableStringify, stableStringifyPretty, usageDir, writeCurrentDocument, writeSnapshot };
|
|
243
|
+
export { CURRENT_FILENAME, type ContractCheckResult, ContractCollectionError, ContractDocument, ContractOperation, ContractSnapshot, ContractSnapshotError, ContractViolation, type DocumentComparison, RELEASED_DIRNAME, type SnapshotFile, USAGE_DIRNAME, type UsageReadResult, type UsageRecord, callersOf, canonicalize, checkContract, collectContractDocument, compareDocuments, compareOperation, compareVersions, currentPath, formatViolations, listSnapshots, newestSnapshot, readCurrentDocument, readSnapshot, readUsageRecords, releasedDir, stableDigest, stableStringify, stableStringifyPretty, subscribersOf, usageDir, writeCurrentDocument, writeSnapshot };
|
package/dist/contract/index.js
CHANGED
|
@@ -2,6 +2,12 @@ import { createHash } from 'crypto';
|
|
|
2
2
|
import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync, statSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
|
|
5
|
+
// src/event/sse/paths.ts
|
|
6
|
+
var DEFAULT_SSE_STREAM_PATH = "/events/stream";
|
|
7
|
+
function sseTokenPath(streamPath) {
|
|
8
|
+
return streamPath.replace(/\/[^/]+$/, "/token");
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
// src/contract/collect.ts
|
|
6
12
|
var ContractCollectionError = class extends Error {
|
|
7
13
|
constructor(message) {
|
|
@@ -104,15 +110,65 @@ function addOperation(name, routeDef, trail, found) {
|
|
|
104
110
|
}
|
|
105
111
|
});
|
|
106
112
|
}
|
|
107
|
-
|
|
113
|
+
var RESERVED_EVENT_NAMES = /* @__PURE__ */ new Set(["connected", "ping"]);
|
|
114
|
+
function byName(a, b) {
|
|
115
|
+
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
116
|
+
}
|
|
117
|
+
function toContractEvent(name, eventDef) {
|
|
118
|
+
const contract = eventDef._contract;
|
|
119
|
+
if (RESERVED_EVENT_NAMES.has(name)) {
|
|
120
|
+
throw new ContractCollectionError(
|
|
121
|
+
`Contracted event "${name}" uses a reserved frame name. The stream itself sends "connected" and "ping" frames, so a client could not tell this event from them. Register the event under another key.`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (!contract.since) {
|
|
125
|
+
throw new ContractCollectionError(
|
|
126
|
+
`Contracted event "${name}" has no "since" version. The version an event first appeared in is part of the promise.`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
if (!eventDef.schema) {
|
|
130
|
+
throw new ContractCollectionError(
|
|
131
|
+
`Contracted event "${name}" declares no payload schema. Its frame carries no data, so there is nothing for the contract to describe. Declare Type.Object({}) and emit {} instead.`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
name,
|
|
136
|
+
since: contract.since,
|
|
137
|
+
...contract.deprecatedIn ? { deprecatedIn: contract.deprecatedIn } : {},
|
|
138
|
+
...contract.removedIn ? { removedIn: contract.removedIn } : {},
|
|
139
|
+
payload: toJsonSchema(eventDef.schema)
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function collectEvents(eventRouter) {
|
|
143
|
+
const contracted = Object.entries(eventRouter?.events ?? {}).filter(([, eventDef]) => eventDef._contract);
|
|
144
|
+
if (contracted.length === 0) {
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
const routerContract = eventRouter._contract;
|
|
148
|
+
if (!routerContract) {
|
|
149
|
+
throw new ContractCollectionError(
|
|
150
|
+
`Event router defineEventRouter({ ${eventRouter.eventNames.join(", ")} }) contracts events but declares no .contract() of its own. Without it the contract cannot say whether a client must exchange a token before opening the stream. Add .contract({ auth: 'none' }) or .contract({ auth: 'tokenExchange' }) to the router.`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
const streamPath = routerContract.streamPath ?? DEFAULT_SSE_STREAM_PATH;
|
|
154
|
+
return {
|
|
155
|
+
streamPath,
|
|
156
|
+
tokenPath: sseTokenPath(streamPath),
|
|
157
|
+
auth: routerContract.auth,
|
|
158
|
+
items: contracted.map(([name, eventDef]) => toContractEvent(name, eventDef)).sort(byName)
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function collectContractDocument(router, eventRouter) {
|
|
108
162
|
const found = /* @__PURE__ */ new Map();
|
|
109
163
|
visitRouter(router, ["router"], found);
|
|
110
|
-
const operations = [...found.values()].map((entry) => entry.operation).sort(
|
|
164
|
+
const operations = [...found.values()].map((entry) => entry.operation).sort(byName);
|
|
165
|
+
const events = collectEvents(eventRouter);
|
|
111
166
|
return {
|
|
112
167
|
documentVersion: 1,
|
|
113
168
|
...router._contractVersion ? { contractVersion: router._contractVersion } : {},
|
|
114
169
|
compatibilityPolicy: "perOperation",
|
|
115
|
-
operations
|
|
170
|
+
operations,
|
|
171
|
+
...events ? { events } : {}
|
|
116
172
|
};
|
|
117
173
|
}
|
|
118
174
|
function canonicalize(value) {
|
|
@@ -279,6 +335,52 @@ function compareOperation(before, after) {
|
|
|
279
335
|
);
|
|
280
336
|
return violations;
|
|
281
337
|
}
|
|
338
|
+
var PAYLOAD_KINDS = {
|
|
339
|
+
"response.field-removed": "event.payload.field-removed",
|
|
340
|
+
"response.field-became-optional": "event.payload.field-became-optional",
|
|
341
|
+
"response.type-changed": "event.payload.type-changed"
|
|
342
|
+
};
|
|
343
|
+
function compareEvent(before, after) {
|
|
344
|
+
const found = [];
|
|
345
|
+
compareSchema(before.payload, after.payload, "payload", { operation: before.name, side: "response", violations: found });
|
|
346
|
+
return found.map(({ kind, operation, ...rest }) => ({ ...rest, kind: PAYLOAD_KINDS[kind] ?? kind, event: operation }));
|
|
347
|
+
}
|
|
348
|
+
function compareStream(before, after) {
|
|
349
|
+
const violations = [];
|
|
350
|
+
if (before.streamPath !== after.streamPath) {
|
|
351
|
+
violations.push({
|
|
352
|
+
kind: "events.stream-path-changed",
|
|
353
|
+
detail: `stream path moved ${before.streamPath} \u2192 ${after.streamPath}; released clients open the old one`
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
if (before.auth !== after.auth) {
|
|
357
|
+
violations.push({
|
|
358
|
+
kind: "events.auth-changed",
|
|
359
|
+
detail: `stream auth changed ${before.auth} \u2192 ${after.auth}; released clients connect the old way`
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
return violations;
|
|
363
|
+
}
|
|
364
|
+
function compareEvents(before, after) {
|
|
365
|
+
if (!before) {
|
|
366
|
+
return { violations: [], removedEvents: [] };
|
|
367
|
+
}
|
|
368
|
+
if (!after) {
|
|
369
|
+
return { violations: [], removedEvents: before.items.map((item) => item.name) };
|
|
370
|
+
}
|
|
371
|
+
const current = new Map(after.items.map((item) => [item.name, item]));
|
|
372
|
+
const violations = compareStream(before, after);
|
|
373
|
+
const removedEvents = [];
|
|
374
|
+
for (const item of before.items) {
|
|
375
|
+
const now = current.get(item.name);
|
|
376
|
+
if (!now) {
|
|
377
|
+
removedEvents.push(item.name);
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
violations.push(...compareEvent(item, now));
|
|
381
|
+
}
|
|
382
|
+
return { violations, removedEvents };
|
|
383
|
+
}
|
|
282
384
|
function compareDocuments(before, after) {
|
|
283
385
|
const current = new Map(after.operations.map((operation) => [operation.name, operation]));
|
|
284
386
|
const violations = [];
|
|
@@ -291,7 +393,12 @@ function compareDocuments(before, after) {
|
|
|
291
393
|
}
|
|
292
394
|
violations.push(...compareOperation(operation, now));
|
|
293
395
|
}
|
|
294
|
-
|
|
396
|
+
const events = compareEvents(before.events, after.events);
|
|
397
|
+
return {
|
|
398
|
+
violations: [...violations, ...events.violations],
|
|
399
|
+
removedOperations,
|
|
400
|
+
removedEvents: events.removedEvents
|
|
401
|
+
};
|
|
295
402
|
}
|
|
296
403
|
var ContractSnapshotError = class extends Error {
|
|
297
404
|
constructor(message) {
|
|
@@ -454,10 +561,15 @@ function parseRecord(file, raw) {
|
|
|
454
561
|
if (!Array.isArray(parsed.operations) || parsed.operations.some((name) => typeof name !== "string")) {
|
|
455
562
|
throw new Error('"operations" must be an array of operation names');
|
|
456
563
|
}
|
|
564
|
+
const events = parsed.events ?? [];
|
|
565
|
+
if (!Array.isArray(events) || events.some((name) => typeof name !== "string")) {
|
|
566
|
+
throw new Error('"events" must be an array of event names');
|
|
567
|
+
}
|
|
457
568
|
return {
|
|
458
569
|
platform: parsed.platform,
|
|
459
570
|
appVersion: parsed.appVersion,
|
|
460
571
|
operations: parsed.operations,
|
|
572
|
+
events,
|
|
461
573
|
file
|
|
462
574
|
};
|
|
463
575
|
}
|
|
@@ -489,6 +601,9 @@ function readUsageRecords(usageDir2) {
|
|
|
489
601
|
function callersOf(operation, records) {
|
|
490
602
|
return records.filter((record) => record.operations.includes(operation));
|
|
491
603
|
}
|
|
604
|
+
function subscribersOf(event, records) {
|
|
605
|
+
return records.filter((record) => (record.events ?? []).includes(event));
|
|
606
|
+
}
|
|
492
607
|
|
|
493
608
|
// src/contract/check.ts
|
|
494
609
|
function checkContract(contractsDir, current) {
|
|
@@ -514,45 +629,54 @@ function checkContract(contractsDir, current) {
|
|
|
514
629
|
}]
|
|
515
630
|
};
|
|
516
631
|
}
|
|
517
|
-
const { violations, removedOperations } = compareDocuments(previous, current);
|
|
632
|
+
const { violations, removedOperations, removedEvents } = compareDocuments(previous, current);
|
|
518
633
|
return {
|
|
519
634
|
baselineVersion: baseline.version,
|
|
520
635
|
warnings: [],
|
|
521
|
-
violations: [...violations, ...judgeRemovals(contractsDir, removedOperations)]
|
|
636
|
+
violations: [...violations, ...judgeRemovals(contractsDir, removedOperations, removedEvents)]
|
|
522
637
|
};
|
|
523
638
|
}
|
|
524
|
-
function judgeRemovals(contractsDir, removedOperations) {
|
|
525
|
-
|
|
639
|
+
function judgeRemovals(contractsDir, removedOperations, removedEvents) {
|
|
640
|
+
const removed = [...removedOperations, ...removedEvents];
|
|
641
|
+
if (removed.length === 0) {
|
|
526
642
|
return [];
|
|
527
643
|
}
|
|
528
644
|
const usage = readUsageRecords(usageDir(contractsDir));
|
|
529
645
|
if (!usage.decidable) {
|
|
530
646
|
return [{
|
|
531
647
|
kind: "usage.undecidable",
|
|
532
|
-
detail: `${
|
|
648
|
+
detail: `${removed.join(", ")} would be removed, but no released client's usage list could be read (${usage.reason}). Not knowing who uses it is not the same as knowing nobody does.`
|
|
533
649
|
}];
|
|
534
650
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
kind: "usage.still-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
651
|
+
return [
|
|
652
|
+
...removedOperations.flatMap((operation) => stillUsed(
|
|
653
|
+
{ kind: "usage.still-called", operation },
|
|
654
|
+
"still called by",
|
|
655
|
+
callersOf(operation, usage.records)
|
|
656
|
+
)),
|
|
657
|
+
...removedEvents.flatMap((event) => stillUsed(
|
|
658
|
+
{ kind: "usage.still-subscribed", event },
|
|
659
|
+
"still subscribed to by",
|
|
660
|
+
subscribersOf(event, usage.records)
|
|
661
|
+
))
|
|
662
|
+
];
|
|
663
|
+
}
|
|
664
|
+
function stillUsed(subject, verb, users) {
|
|
665
|
+
if (users.length === 0) {
|
|
666
|
+
return [];
|
|
546
667
|
}
|
|
547
|
-
return
|
|
668
|
+
return [{
|
|
669
|
+
...subject,
|
|
670
|
+
detail: `${verb} ${users.map((user) => `${user.platform} ${user.appVersion}`).join(", ")}`
|
|
671
|
+
}];
|
|
548
672
|
}
|
|
549
673
|
function formatViolations(violations) {
|
|
550
674
|
return violations.map((violation) => {
|
|
551
|
-
const where = [violation.operation, violation.location].filter(Boolean).join(" ");
|
|
675
|
+
const where = [violation.operation ?? violation.event, violation.location].filter(Boolean).join(" ");
|
|
552
676
|
return ` - [${violation.kind}]${where ? ` ${where}` : ""}: ${violation.detail}`;
|
|
553
677
|
}).join("\n");
|
|
554
678
|
}
|
|
555
679
|
|
|
556
|
-
export { CURRENT_FILENAME, ContractCollectionError, ContractSnapshotError, RELEASED_DIRNAME, USAGE_DIRNAME, callersOf, canonicalize, checkContract, collectContractDocument, compareDocuments, compareOperation, compareVersions, currentPath, formatViolations, listSnapshots, newestSnapshot, readCurrentDocument, readSnapshot, readUsageRecords, releasedDir, stableDigest, stableStringify, stableStringifyPretty, usageDir, writeCurrentDocument, writeSnapshot };
|
|
680
|
+
export { CURRENT_FILENAME, ContractCollectionError, ContractSnapshotError, RELEASED_DIRNAME, USAGE_DIRNAME, callersOf, canonicalize, checkContract, collectContractDocument, compareDocuments, compareOperation, compareVersions, currentPath, formatViolations, listSnapshots, newestSnapshot, readCurrentDocument, readSnapshot, readUsageRecords, releasedDir, stableDigest, stableStringify, stableStringifyPretty, subscribersOf, usageDir, writeCurrentDocument, writeSnapshot };
|
|
557
681
|
//# sourceMappingURL=index.js.map
|
|
558
682
|
//# sourceMappingURL=index.js.map
|