stitchkit 0.81.0 → 0.83.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +6613 -0
  2. package/README.md +4 -0
  3. package/dist/agent-runtime/events.d.ts +9 -2
  4. package/dist/agent-runtime/events.d.ts.map +1 -1
  5. package/dist/agent-runtime/observability.d.ts +9 -2
  6. package/dist/agent-runtime/observability.d.ts.map +1 -1
  7. package/dist/agent-runtime-harness.js +2 -2
  8. package/dist/agent-runtime.js +4 -4
  9. package/dist/application/events.d.ts +9 -2
  10. package/dist/application/events.d.ts.map +1 -1
  11. package/dist/application/latest-sink.d.ts +12 -2
  12. package/dist/application/latest-sink.d.ts.map +1 -1
  13. package/dist/application-opentelemetry.js +2 -1
  14. package/dist/application.js +4 -4
  15. package/dist/{index-6s7n2v50.js → index-64ew0vnj.js} +15 -10
  16. package/dist/{index-a59da114.js → index-7z1h3kbr.js} +61 -15
  17. package/dist/{index-1dd82z59.js → index-pq7ak4k8.js} +3 -3
  18. package/dist/internal/observability-sink.d.ts +49 -2
  19. package/dist/internal/observability-sink.d.ts.map +1 -1
  20. package/dist/internal/upgrade-plan.d.ts +18 -0
  21. package/dist/internal/upgrade-plan.d.ts.map +1 -0
  22. package/dist/observability/audit.d.ts +20 -4
  23. package/dist/observability/audit.d.ts.map +1 -1
  24. package/dist/observability/index.d.ts +1 -1
  25. package/dist/observability/index.d.ts.map +1 -1
  26. package/dist/observability/index.js +30 -15
  27. package/dist/observability/status.d.ts +1 -0
  28. package/dist/observability/status.d.ts.map +1 -1
  29. package/dist/release/socket.d.ts +14 -1
  30. package/dist/release/socket.d.ts.map +1 -1
  31. package/dist/tracking/contract.d.ts +11 -0
  32. package/dist/tracking/contract.d.ts.map +1 -1
  33. package/dist/tracking-server.d.ts +1 -0
  34. package/dist/tracking-server.d.ts.map +1 -1
  35. package/dist/tracking.js +1 -0
  36. package/dist/upgrade-cli.d.ts +27 -0
  37. package/dist/upgrade-cli.d.ts.map +1 -0
  38. package/dist/upgrade-cli.js +177 -0
  39. package/llms-full.txt +185 -17
  40. package/package.json +6 -2
@@ -3,8 +3,10 @@ import {
3
3
  ObservabilitySinkStatusSchema,
4
4
  ObservabilityStatusSchema,
5
5
  aggregateObservabilityStatus,
6
- createBoundedSinkManager
7
- } from "../index-a59da114.js";
6
+ assertDrainBound,
7
+ createBoundedSinkManager,
8
+ withinBound
9
+ } from "../index-7z1h3kbr.js";
8
10
  import {
9
11
  measureSize,
10
12
  redact,
@@ -115,7 +117,9 @@ function createObservability(config) {
115
117
  const requestManager = config.request ? createSinkManager(config.request) : undefined;
116
118
  const toolManager = config.tools ? createSinkManager(config.tools) : undefined;
117
119
  let closed = false;
118
- let closePromise;
120
+ let drain;
121
+ let drainStartedAt = 0;
122
+ let unbounded;
119
123
  const request = config.request ? {
120
124
  includePayload: config.request.includePayload ?? false,
121
125
  complete: ({ context, statusCode, durationMs, payload, outcome }) => {
@@ -232,23 +236,34 @@ function createObservability(config) {
232
236
  return {
233
237
  ...request && { request },
234
238
  toolCall: toolCall ?? {},
235
- async flush() {
236
- await Promise.all([requestManager?.flush(), toolManager?.flush()]);
239
+ flush(bound) {
240
+ assertDrainBound(bound);
241
+ return withinBound(Promise.all([requestManager?.flush(), toolManager?.flush()]), bound);
237
242
  },
238
243
  getStatus,
239
- close() {
240
- if (!closePromise) {
244
+ close(bound) {
245
+ assertDrainBound(bound);
246
+ if (!drain) {
241
247
  closed = true;
242
- const startedAt = performance.now();
243
- closePromise = Promise.all([requestManager?.close(), toolManager?.close()]).then(() => {
244
- const status = getStatus();
245
- return ObservabilityDrainReportSchema.parse({
246
- ...status,
247
- durationMs: performance.now() - startedAt
248
- });
248
+ drainStartedAt = performance.now();
249
+ drain = Promise.all([requestManager?.close(), toolManager?.close()]).then(() => {
250
+ return;
251
+ });
252
+ }
253
+ const startedAt = drainStartedAt;
254
+ const report = () => {
255
+ const status = getStatus();
256
+ return ObservabilityDrainReportSchema.parse({
257
+ ...status,
258
+ durationMs: performance.now() - startedAt,
259
+ drained: status.total.pending + status.total.preparing === 0
249
260
  });
261
+ };
262
+ if (!bound?.signal && bound?.timeoutMs === undefined) {
263
+ unbounded ??= withinBound(drain, undefined).then(report);
264
+ return unbounded;
250
265
  }
251
- return closePromise;
266
+ return withinBound(drain, bound).then(report);
252
267
  }
253
268
  };
254
269
  }
@@ -98,6 +98,7 @@ export declare const ObservabilityDrainReportSchema: z.ZodReadonly<z.ZodObject<{
98
98
  closed: z.ZodBoolean;
99
99
  }, z.core.$strip>>;
100
100
  durationMs: z.ZodNumber;
101
+ drained: z.ZodBoolean;
101
102
  }, z.core.$strip>>;
102
103
  export type ObservabilityDrainReport = z.infer<typeof ObservabilityDrainReportSchema>;
103
104
  /** Build and freeze the aggregate without exposing mutable counters. */
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/observability/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,yEAAyE;AACzE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;kBAc7B,CAAC;AAEd,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AASpF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAA6C,CAAC;AAEpF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,sFAAsF;AACtF,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAE9B,CAAC;AAEd,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAiBtF,wEAAwE;AACxE,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,SAAS,uBAAuB,EAAE,EAC5C,MAAM,EAAE,OAAO,GACd,uBAAuB,CAiBzB"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/observability/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,yEAAyE;AACzE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;kBAc7B,CAAC;AAEd,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AASpF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAA6C,CAAC;AAEpF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,sFAAsF;AACtF,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAoB9B,CAAC;AAEd,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC;AAiBtF,wEAAwE;AACxE,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,SAAS,uBAAuB,EAAE,EAC5C,MAAM,EAAE,OAAO,GACd,uBAAuB,CAiBzB"}
@@ -1,6 +1,19 @@
1
1
  import type { ReleaseMarker } from './marker.js';
2
2
  import type { ReleaseWatcher } from './watcher.js';
3
- /** The little of a Socket.IO server this binding uses — structural, no peer import. */
3
+ /**
4
+ * The little of a Socket.IO server this binding uses — structural, no peer
5
+ * import.
6
+ *
7
+ * `emit` is declared over `string` because the event name is configurable. A
8
+ * **typed** `Server<ClientToServer, ServerToClient>` narrows its own `emit` to
9
+ * the names in its map, so it satisfies this only once that map declares the
10
+ * event — `release: (payload: { buildId: string | null }) => void`, or whatever
11
+ * `options.event` renames it to. Until then the compiler reports a structural
12
+ * mismatch between two large socket.io types, which reads like a defect in this
13
+ * binding and is a missing line in the application's event map. Adding it is
14
+ * step 3 of the guide's adoption list for exactly this reason: the same
15
+ * declaration is what lets the application's own `on` know the event.
16
+ */
4
17
  export interface ReleaseSocketServer {
5
18
  on(event: 'connection', handler: (socket: ReleaseSocketEmitter) => void): unknown;
6
19
  emit(event: string, payload: {
@@ -1 +1 @@
1
- {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/release/socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IAClC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC;IAClF,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC;CACnE;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC;CACnE;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC;IACnF,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC;CACtF;AAED,MAAM,WAAW,oBAAoB;IACnC,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,mBAAmB,EACvB,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,oBAAoB,GAAG;IAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAO,GACrE,MAAM,IAAI,CAcZ;AAED,qEAAqE;AACrE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,oBAAyB,GACjC,MAAM,IAAI,CAQZ"}
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/release/socket.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC;IAClF,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC;CACnE;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC;CACnE;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC;IACnF,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC;CACtF;AAED,MAAM,WAAW,oBAAoB;IACnC,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,mBAAmB,EACvB,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,oBAAoB,GAAG;IAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAO,GACrE,MAAM,IAAI,CAcZ;AAED,qEAAqE;AACrE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,cAAc,EACvB,OAAO,GAAE,oBAAyB,GACjC,MAAM,IAAI,CAQZ"}
@@ -27,6 +27,7 @@ export type TrackingContractEndpoints<TSchemas extends TrackingSchemas<z.ZodObje
27
27
  track: {
28
28
  method: 'POST';
29
29
  path: '/events';
30
+ expose: readonly ['HTTP'];
30
31
  desc: string;
31
32
  input: TSchemas['request'];
32
33
  output: TSchemas['response'];
@@ -40,6 +41,16 @@ export type TrackingContractEndpoints<TSchemas extends TrackingSchemas<z.ZodObje
40
41
  * `sendUnloadBeacon` with a string body — the only body a document that is
41
42
  * being unloaded can deliver to another origin (ADR 0165) — and the server
42
43
  * therefore needs an explicit `cors.origin` allow-list for it to arrive.
44
+ *
45
+ * **Both endpoints are HTTP-only, and that is not a formality.** An endpoint
46
+ * with no `expose` is a tool on MCP and AGENT by default, and this contract is
47
+ * built here rather than by the application's own contract factory — so a
48
+ * project that sets `toolExposure: 'explicit'` for everything it authors was
49
+ * still handed a `track` tool it never asked for. An agent has nothing to gain
50
+ * from a browser-event ingest and one thing to lose by having it: writes into
51
+ * the application's visitor data, under its own name, indistinguishable
52
+ * afterwards from a real visitor's. `bootstrap` said `['HTTP']` from the start;
53
+ * `track` not saying it was an omission, not a decision.
43
54
  */
44
55
  export declare function createTrackingContract<TType extends string, TScope extends string>(config: TrackingContractConfig<TType, undefined, TScope>): ContractDef<TrackingContractEndpoints<TrackingSchemas<z.ZodObject<TrackingEventShape<TType>>>>, TScope>;
45
56
  export declare function createTrackingContract<TType extends string, TExtras extends z.ZodRawShape, TScope extends string>(config: TrackingContractConfig<TType, TExtras, TScope>): ContractDef<TrackingContractEndpoints<TrackingSchemas<z.ZodObject<TrackingEventShape<TType> & TExtras>>>, TScope>;
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/tracking/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC3B,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,sBAAsB,CACrC,KAAK,SAAS,MAAM,EACpB,OAAO,SAAS,CAAC,CAAC,WAAW,GAAG,SAAS,EACzC,MAAM,SAAS,MAAM,CACrB,SAAQ,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC;IAC7C,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,yFAAyF;AACzF,MAAM,MAAM,yBAAyB,CAAC,QAAQ,SAAS,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI;IACrF,SAAS,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,QAAQ,CAAC;QACf,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;KAC/B,CAAC;IACF,KAAK,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,SAAS,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC3B,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC7B,cAAc,EAAE,IAAI,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,SAAS,MAAM,EAAE,MAAM,SAAS,MAAM,EAChF,MAAM,EAAE,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,GACvD,WAAW,CACZ,yBAAyB,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAClF,MAAM,CACP,CAAC;AACF,wBAAgB,sBAAsB,CACpC,KAAK,SAAS,MAAM,EACpB,OAAO,SAAS,CAAC,CAAC,WAAW,EAC7B,MAAM,SAAS,MAAM,EAErB,MAAM,EAAE,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,GACrD,WAAW,CACZ,yBAAyB,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC5F,MAAM,CACP,CAAC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/tracking/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC3B,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,sBAAsB,CACrC,KAAK,SAAS,MAAM,EACpB,OAAO,SAAS,CAAC,CAAC,WAAW,GAAG,SAAS,EACzC,MAAM,SAAS,MAAM,CACrB,SAAQ,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC;IAC7C,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,yFAAyF;AACzF,MAAM,MAAM,yBAAyB,CAAC,QAAQ,SAAS,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI;IACrF,SAAS,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,QAAQ,CAAC;QACf,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;KAC/B,CAAC;IACF,KAAK,EAAE;QACL,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,SAAS,CAAC;QAChB,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC3B,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC7B,cAAc,EAAE,IAAI,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,SAAS,MAAM,EAAE,MAAM,SAAS,MAAM,EAChF,MAAM,EAAE,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,GACvD,WAAW,CACZ,yBAAyB,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAClF,MAAM,CACP,CAAC;AACF,wBAAgB,sBAAsB,CACpC,KAAK,SAAS,MAAM,EACpB,OAAO,SAAS,CAAC,CAAC,WAAW,EAC7B,MAAM,SAAS,MAAM,EAErB,MAAM,EAAE,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,GACrD,WAAW,CACZ,yBAAyB,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAC5F,MAAM,CACP,CAAC"}
@@ -5,6 +5,7 @@
5
5
  * back; `issueVisitLease` runs the visit algorithm over a store interface the
6
6
  * application implements. No database, no schema, no domain. → ADR 0166.
7
7
  */
8
+ export type { TrackingDisposition, VisitBootstrapResponse, VisitEntryContext, } from './tracking/schemas.js';
8
9
  export { type ActiveIntervalOptions, type ActiveTimeInterval, activeIntervalOf, } from './tracking/server/active-interval.js';
9
10
  export { DEFAULT_BOT_USER_AGENT_PATTERN, isBotUserAgent } from './tracking/server/bot.js';
10
11
  export { type DispositionEvent, type DispositionInput, type DispositionResult, dispositionTrackingBatch, type KnownVisit, } from './tracking/server/disposition.js';
@@ -1 +1 @@
1
- {"version":3,"file":"tracking-server.d.ts","sourceRoot":"","sources":["../src/tracking-server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,gBAAgB,GACjB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,8BAA8B,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,wBAAwB,EACxB,KAAK,UAAU,GAChB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"tracking-server.d.ts","sourceRoot":"","sources":["../src/tracking-server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,gBAAgB,GACjB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,8BAA8B,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,wBAAwB,EACxB,KAAK,UAAU,GAChB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,cAAc,GACpB,MAAM,+BAA+B,CAAC"}
package/dist/tracking.js CHANGED
@@ -778,6 +778,7 @@ function createTrackingContract(config) {
778
778
  track: {
779
779
  method: "POST",
780
780
  path: "/events",
781
+ expose: ["HTTP"],
781
782
  desc: "Batch track browser events",
782
783
  input: schemas.request,
783
784
  output: schemas.response,
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ export interface UpgradeCliResult {
3
+ /** What to write to stdout. */
4
+ readonly output: string;
5
+ /** Process exit code — 0 when the plan (or "nothing to do") was produced. */
6
+ readonly code: number;
7
+ }
8
+ /**
9
+ * The whole command as a function of its arguments and the filesystem, so the
10
+ * gate can exercise the paths that matter — a project with no stitchkit
11
+ * installed, a range that runs backwards, a changelog the package did not ship.
12
+ */
13
+ export declare function runUpgradeCli(argv: readonly string[]): UpgradeCliResult;
14
+ /**
15
+ * Was this file executed as a program, rather than imported?
16
+ *
17
+ * Through the real install path that is a **symlink** question, not a string
18
+ * one: npm and bun link `node_modules/.bin/stitchkit` at the built file, Node
19
+ * keeps the link in `argv[1]` and resolves `import.meta.url` to its target. A
20
+ * direct comparison of the two is therefore false for every consumer, and the
21
+ * binary becomes a silent no-op — exit 0, no output, nothing to notice — while
22
+ * running the same file in place works perfectly. Both arguments are passed in
23
+ * so this is decidable without launching a process: under Bun `argv[1]` is
24
+ * already resolved, so a spawned symlink proves nothing about Node.
25
+ */
26
+ export declare function isDirectInvocation(invoked: string | undefined, self: string): boolean;
27
+ //# sourceMappingURL=upgrade-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade-cli.d.ts","sourceRoot":"","sources":["../src/upgrade-cli.ts"],"names":[],"mappings":";AA4DA,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,CAqCvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CASrF"}
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/upgrade-cli.ts
4
+ import { readFileSync, realpathSync } from "node:fs";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+
8
+ // src/internal/upgrade-plan.ts
9
+ function semverParts(version) {
10
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
11
+ if (!match)
12
+ throw new Error(`Expected an exact semver, received "${version}"`);
13
+ const [, major, minor, patch] = match;
14
+ if (major === undefined || minor === undefined || patch === undefined) {
15
+ throw new Error(`Expected an exact semver, received "${version}"`);
16
+ }
17
+ return [Number(major), Number(minor), Number(patch)];
18
+ }
19
+ function compareSemver(left, right) {
20
+ const a = semverParts(left);
21
+ const b = semverParts(right);
22
+ for (const index of [0, 1, 2]) {
23
+ const difference = a[index] - b[index];
24
+ if (difference !== 0)
25
+ return difference;
26
+ }
27
+ return 0;
28
+ }
29
+ function planUpgrade(changelog, from, to) {
30
+ semverParts(from);
31
+ semverParts(to);
32
+ if (compareSemver(from, to) >= 0) {
33
+ throw new Error(`Upgrade range must increase: ${from} → ${to}`);
34
+ }
35
+ const releases = [...changelog.matchAll(/^## \[(\d+\.\d+\.\d+)\].*$/gm)];
36
+ const changes = [];
37
+ for (const [index, release] of releases.entries()) {
38
+ const version = release[1];
39
+ if (version === undefined)
40
+ continue;
41
+ if (compareSemver(version, from) <= 0 || compareSemver(version, to) > 0)
42
+ continue;
43
+ const bodyStart = (release.index ?? 0) + release[0].length;
44
+ const bodyEnd = releases[index + 1]?.index ?? changelog.length;
45
+ const body = changelog.slice(bodyStart, bodyEnd);
46
+ const breakingHeader = /^### ⚠️ Breaking changes\s*$/m.exec(body);
47
+ if (!breakingHeader)
48
+ continue;
49
+ const breakingStart = (breakingHeader.index ?? 0) + breakingHeader[0].length;
50
+ const afterHeader = body.slice(breakingStart);
51
+ const nextSection = /^### /m.exec(afterHeader);
52
+ const markdown = afterHeader.slice(0, nextSection?.index ?? afterHeader.length).trim();
53
+ const who = /^\*\*Who must act:\*\*\s*([\s\S]*?)(?=\n\s*\n|\n[-*] )/m.exec(markdown);
54
+ changes.push({
55
+ version,
56
+ whoMustAct: who?.[1]?.replace(/\s+/g, " ").trim() ?? "Not declared in this legacy changelog section.",
57
+ markdown
58
+ });
59
+ }
60
+ return changes.sort((left, right) => compareSemver(left.version, right.version));
61
+ }
62
+ function renderUpgradePlan(changes, from, to) {
63
+ const header = `# Stitchkit upgrade ${from} → ${to}`;
64
+ if (changes.length === 0)
65
+ return `${header}
66
+
67
+ No breaking sections in this range.
68
+ `;
69
+ return `${header}
70
+
71
+ ${changes.map((change) => `## ${change.version}
72
+
73
+ **Who must act:** ${change.whoMustAct}
74
+
75
+ ${change.markdown.replace(/^\*\*Who must act:\*\*[\s\S]*?(?=\n\s*\n|\n[-*] )/m, "").trim()}`).join(`
76
+
77
+ `)}
78
+ `;
79
+ }
80
+
81
+ // src/upgrade-cli.ts
82
+ var USAGE = `stitchkit upgrade — print every breaking change between the installed version and this one
83
+
84
+ bunx stitchkit@latest upgrade in a project that depends on stitchkit
85
+ npx stitchkit@latest upgrade
86
+
87
+ Options
88
+ --from <version> installed version (default: the stitchkit in ./node_modules)
89
+ --to <version> target version (default: the version of this package)
90
+ --cwd <dir> project to read the installed version from (default: .)
91
+ --changelog <path> changelog to plan from (default: the one in this package)
92
+ `;
93
+ function option(argv, name) {
94
+ const index = argv.indexOf(`--${name}`);
95
+ if (index < 0)
96
+ return;
97
+ const value = argv[index + 1];
98
+ if (value === undefined || value.startsWith("--")) {
99
+ throw new Error(`--${name} needs a value`);
100
+ }
101
+ return value;
102
+ }
103
+ function packageRoot() {
104
+ return resolve(dirname(fileURLToPath(import.meta.url)), "..");
105
+ }
106
+ function versionOf(packageJsonPath) {
107
+ let text;
108
+ try {
109
+ text = readFileSync(packageJsonPath, "utf8");
110
+ } catch {
111
+ return;
112
+ }
113
+ const parsed = JSON.parse(text);
114
+ if (typeof parsed !== "object" || parsed === null || !("version" in parsed))
115
+ return;
116
+ const { version } = parsed;
117
+ return typeof version === "string" ? version : undefined;
118
+ }
119
+ function runUpgradeCli(argv) {
120
+ if (argv.includes("--help") || argv.includes("-h") || argv.length === 0) {
121
+ return { output: USAGE, code: 0 };
122
+ }
123
+ const [command] = argv;
124
+ if (command !== "upgrade") {
125
+ return { output: `Unknown command "${command}".
126
+
127
+ ${USAGE}`, code: 1 };
128
+ }
129
+ const root = packageRoot();
130
+ const to = option(argv, "to") ?? versionOf(join(root, "package.json"));
131
+ if (to === undefined) {
132
+ throw new Error(`Cannot read the version of the stitchkit at ${root}`);
133
+ }
134
+ const cwd = resolve(option(argv, "cwd") ?? process.cwd());
135
+ const from = option(argv, "from") ?? versionOf(join(cwd, "node_modules", "stitchkit", "package.json"));
136
+ if (from === undefined) {
137
+ throw new Error(`No stitchkit found in ${join(cwd, "node_modules")} — run this in the project that depends on it, or pass --from <installed version>`);
138
+ }
139
+ if (from === to) {
140
+ return { output: `Already on ${to}. Nothing to upgrade.
141
+ `, code: 0 };
142
+ }
143
+ const changelogPath = option(argv, "changelog") ?? join(root, "CHANGELOG.md");
144
+ let changelog;
145
+ try {
146
+ changelog = readFileSync(changelogPath, "utf8");
147
+ } catch {
148
+ throw new Error(`Cannot read the changelog at ${changelogPath}`);
149
+ }
150
+ return { output: renderUpgradePlan(planUpgrade(changelog, from, to), from, to), code: 0 };
151
+ }
152
+ function isDirectInvocation(invoked, self) {
153
+ if (invoked === undefined)
154
+ return false;
155
+ if (invoked === self || pathToFileURL(invoked).href === pathToFileURL(self).href)
156
+ return true;
157
+ try {
158
+ return realpathSync(invoked) === realpathSync(self);
159
+ } catch {
160
+ return false;
161
+ }
162
+ }
163
+ if (isDirectInvocation(process.argv[1], fileURLToPath(import.meta.url))) {
164
+ try {
165
+ const { output, code } = runUpgradeCli(process.argv.slice(2));
166
+ process.stdout.write(output);
167
+ process.exit(code);
168
+ } catch (error) {
169
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}
170
+ `);
171
+ process.exit(1);
172
+ }
173
+ }
174
+ export {
175
+ runUpgradeCli,
176
+ isDirectInvocation
177
+ };