stitchkit 0.60.1 → 0.61.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.
- package/dist/application/kernel.d.ts +23 -0
- package/dist/application/kernel.d.ts.map +1 -1
- package/dist/application/server-resource.d.ts.map +1 -1
- package/dist/application.d.ts +1 -1
- package/dist/application.d.ts.map +1 -1
- package/dist/application.js +11 -6
- package/dist/browser/socket-io.d.ts +47 -0
- package/dist/browser/socket-io.d.ts.map +1 -1
- package/dist/browser/stream.d.ts +23 -0
- package/dist/browser/stream.d.ts.map +1 -1
- package/dist/contract/index.js +1 -1
- package/dist/{index-t8xrqc9g.js → index-413xk7ga.js} +1 -1
- package/dist/{index-82e74yfx.js → index-eabpd4tb.js} +56 -7
- package/dist/{index-2cgbdckv.js → index-s1tywej8.js} +88 -19
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +213 -17
- package/dist/internal/optional-peer.d.ts +14 -0
- package/dist/internal/optional-peer.d.ts.map +1 -0
- package/dist/node.js +1 -1
- package/dist/realtime/contract.d.ts +7 -1
- package/dist/realtime/contract.d.ts.map +1 -1
- package/dist/realtime/index.d.ts +2 -1
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/rejected-frame.d.ts +86 -0
- package/dist/realtime/rejected-frame.d.ts.map +1 -0
- package/dist/realtime/request.d.ts +24 -0
- package/dist/realtime/request.d.ts.map +1 -1
- package/dist/realtime/socket.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +196 -3
- package/dist/server/socket-io.d.ts.map +1 -1
- package/dist/server/stream.d.ts.map +1 -1
- package/dist/server/streaming-route.d.ts +130 -0
- package/dist/server/streaming-route.d.ts.map +1 -0
- package/dist/testing.js +1 -1
- package/llms-full.txt +364 -23
- package/package.json +2 -2
|
@@ -25,9 +25,32 @@ export declare const ApplicationShutdownOptionsSchema: z.ZodObject<{
|
|
|
25
25
|
signal: z.ZodOptional<z.ZodCustom<AbortSignal, AbortSignal>>;
|
|
26
26
|
}, z.core.$strip>;
|
|
27
27
|
export type ApplicationShutdownOptions = z.input<typeof ApplicationShutdownOptionsSchema>;
|
|
28
|
+
/**
|
|
29
|
+
* The budget this application spends on stopping — and the one thing a failed
|
|
30
|
+
* startup's rollback had no way to know.
|
|
31
|
+
*
|
|
32
|
+
* A rollback happens inside `start()`, so there is no call for a caller to pass
|
|
33
|
+
* options to. The budget therefore has to be declared where the application is,
|
|
34
|
+
* and once it is declared there it is also the sensible default for
|
|
35
|
+
* `shutdown()` with no options: one number for "how long this application may
|
|
36
|
+
* take to stop", not two that can disagree.
|
|
37
|
+
*
|
|
38
|
+
* `signal` is deliberately absent. A budget is a property of the application; a
|
|
39
|
+
* signal belongs to the one call that carries it.
|
|
40
|
+
*/
|
|
41
|
+
export declare const ApplicationShutdownBudgetSchema: z.ZodObject<{
|
|
42
|
+
gracePeriodMs: z.ZodDefault<z.ZodNumber>;
|
|
43
|
+
forceTimeoutMs: z.ZodDefault<z.ZodNumber>;
|
|
44
|
+
}, z.core.$strip>;
|
|
45
|
+
export type ApplicationShutdownBudget = z.input<typeof ApplicationShutdownBudgetSchema>;
|
|
28
46
|
export interface ApplicationConfig {
|
|
29
47
|
readonly id: string;
|
|
30
48
|
readonly resources?: readonly ManagedResource[];
|
|
49
|
+
/**
|
|
50
|
+
* How long stopping may take — for `shutdown()` called with no options, and
|
|
51
|
+
* for the rollback of a failed `start()`, which has no other way to be told.
|
|
52
|
+
*/
|
|
53
|
+
readonly shutdown?: ApplicationShutdownBudget;
|
|
31
54
|
readonly onSnapshot?: (snapshot: ApplicationSnapshot) => void | Promise<void>;
|
|
32
55
|
/**
|
|
33
56
|
* Observe why a phase failed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/application/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,YAAY,CAAC;AACpB,OAAO,EAIL,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,EAE9B,KAAK,mBAAmB,EAGzB,MAAM,WAAW,CAAC;AAEnB,6EAA6E;AAC7E,MAAM,MAAM,wBAAwB,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/application/kernel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,YAAY,CAAC;AACpB,OAAO,EAIL,KAAK,2BAA2B,EAChC,KAAK,yBAAyB,EAE9B,KAAK,mBAAmB,EAGzB,MAAM,WAAW,CAAC;AAEnB,6EAA6E;AAC7E,MAAM,MAAM,wBAAwB,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AA8DvF,wEAAwE;AACxE,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAC;IACzC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC;;;;iBAI3C,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE1F;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,+BAA+B;;;iBAG1C,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAChD;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IAC9C,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5F;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,IAAI,yBAAyB,GAAG,IAAI,CAAC;IAC5C,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,oBAAoB,CAAC;IACzC,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACtC,WAAW,IAAI,mBAAmB,CAAC;IACnC,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,0BAA0B,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC;CACpF;AAED;;;;;;;;;GASG;AACH,qBAAa,yBAA0B,SAAQ,QAAQ,CAAC,2BAA2B,CAAC;IAClF,cAGC;CACF;AA2BD,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAgzB9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-resource.d.ts","sourceRoot":"","sources":["../../src/application/server-resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,WAAW,2BAA2B,CAAC,QAAQ;IACnD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,QAAQ,EAC5C,MAAM,EAAE,2BAA2B,CAAC,QAAQ,CAAC,GAC5C,eAAe,
|
|
1
|
+
{"version":3,"file":"server-resource.d.ts","sourceRoot":"","sources":["../../src/application/server-resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAkB,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,WAAW,2BAA2B,CAAC,QAAQ;IACnD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACvF,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,QAAQ,EAC5C,MAAM,EAAE,2BAA2B,CAAC,QAAQ,CAAC,GAC5C,eAAe,CAmGjB"}
|
package/dist/application.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { type ActivityId, ActivityIdSchema, type ActivityLiveState, ActivityLiveStateSchema, type ActivityProjection, type ActivityProjectionConfig, type ActivityProjectionSubscriberError, type ActivitySnapshot, ActivitySnapshotSchema, type ActivityStageId, ActivityStageIdSchema, type ActivityStageSnapshot, ActivityStageSnapshotSchema, type ActivityToken, ActivityTokenBrand, type ActivityTransition, createActivityProjection, } from './application/activity';
|
|
2
2
|
export { type ApplicationEventSink, type ApplicationEventSinkConfig, type ApplicationLifecycleEvent, ApplicationLifecycleEventSchema, applicationLifecycleEvent, createApplicationEventSink, } from './application/events';
|
|
3
3
|
export { type ApplicationHealthHandlerOptions, ApplicationHealthHandlerOptionsSchema, type ApplicationOperationalHandlers, type ApplicationOperationalHandlersOptions, ApplicationOperationalHandlersOptionsSchema, createApplicationHealthHandler, createApplicationOperationalHandlers, } from './application/health';
|
|
4
|
-
export { type ApplicationAdmission, ApplicationAdmissionError, type ApplicationConfig, type ApplicationHandle, type ApplicationOperationLease, type ApplicationResourceFailure, type ApplicationResourcePhase, type ApplicationShutdownOptions, ApplicationShutdownOptionsSchema, createApplication, } from './application/kernel';
|
|
4
|
+
export { type ApplicationAdmission, ApplicationAdmissionError, type ApplicationConfig, type ApplicationHandle, type ApplicationOperationLease, type ApplicationResourceFailure, type ApplicationResourcePhase, type ApplicationShutdownBudget, ApplicationShutdownBudgetSchema, type ApplicationShutdownOptions, ApplicationShutdownOptionsSchema, createApplication, } from './application/kernel';
|
|
5
5
|
export { type ApplicationSnapshotSink, type ApplicationSnapshotSinkConfig, type ApplicationSnapshotSinkError, type ApplicationSnapshotSinkStatus, ApplicationSnapshotSinkStatusSchema, createApplicationSnapshotSink, type RevisionedApplicationSnapshot, } from './application/latest-sink';
|
|
6
6
|
export { defineManagedResource, type ManagedResource, type ManagedResourceContext, type ManagedResourceStartResult, } from './application/resource';
|
|
7
7
|
export { createManagedSchedule, type ManagedSchedule, type ManagedScheduleClock, type ManagedScheduleConfig, type ManagedScheduleDescriptor, ManagedScheduleDescriptorSchema, type ManagedScheduleErrorPolicy, ManagedScheduleErrorPolicySchema, type ManagedScheduleOverlap, ManagedScheduleOverlapSchema, type ManagedScheduleRunContext, type ManagedScheduleStatus, ManagedScheduleStatusSchema, type ManagedScheduleTimer, } from './application/schedule';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EACtC,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,aAAa,EAClB,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,+BAA+B,EACpC,qCAAqC,EACrC,KAAK,8BAA8B,EACnC,KAAK,qCAAqC,EAC1C,2CAA2C,EAC3C,8BAA8B,EAC9B,oCAAoC,GACrC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,oBAAoB,EACzB,yBAAyB,EACzB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,gCAAgC,EAChC,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,mCAAmC,EACnC,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,GAChC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,gCAAgC,EAChC,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,4BAA4B,EACjC,kCAAkC,EAClC,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,0BAA0B,EAC1B,KAAK,2BAA2B,EAChC,iCAAiC,EACjC,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,2BAA2B,EAChC,iCAAiC,EACjC,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,KAAK,oBAAoB,EACzB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,2BAA2B,EAChC,qBAAqB,GACtB,MAAM,+BAA+B,CAAC"}
|
|
1
|
+
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../src/application.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EACf,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EACtC,KAAK,gBAAgB,EACrB,sBAAsB,EACtB,KAAK,eAAe,EACpB,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,aAAa,EAClB,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,+BAA+B,EACpC,qCAAqC,EACrC,KAAK,8BAA8B,EACnC,KAAK,qCAAqC,EAC1C,2CAA2C,EAC3C,8BAA8B,EAC9B,oCAAoC,GACrC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,oBAAoB,EACzB,yBAAyB,EACzB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,gCAAgC,EAChC,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,EACjC,KAAK,6BAA6B,EAClC,mCAAmC,EACnC,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,GAChC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,gCAAgC,EAChC,KAAK,sBAAsB,EAC3B,4BAA4B,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,2BAA2B,EAC3B,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,4BAA4B,EACjC,kCAAkC,EAClC,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,aAAa,EAClB,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,0BAA0B,EAC1B,KAAK,2BAA2B,EAChC,iCAAiC,EACjC,KAAK,yBAAyB,EAC9B,+BAA+B,EAC/B,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,KAAK,2BAA2B,EAChC,iCAAiC,EACjC,KAAK,uBAAuB,EAC5B,6BAA6B,EAC7B,KAAK,oBAAoB,EACzB,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,2BAA2B,EAChC,qBAAqB,GACtB,MAAM,+BAA+B,CAAC"}
|
package/dist/application.js
CHANGED
|
@@ -19,9 +19,10 @@ import {
|
|
|
19
19
|
} from "./index-x8v8b7rc.js";
|
|
20
20
|
import {
|
|
21
21
|
ApplicationAdmissionError,
|
|
22
|
+
ApplicationShutdownBudgetSchema,
|
|
22
23
|
ApplicationShutdownOptionsSchema,
|
|
23
24
|
createApplication
|
|
24
|
-
} from "./index-
|
|
25
|
+
} from "./index-eabpd4tb.js";
|
|
25
26
|
import {
|
|
26
27
|
ApplicationAdmissionSnapshotSchema,
|
|
27
28
|
ApplicationHealthSchema,
|
|
@@ -119,16 +120,19 @@ function createApplicationOperationalHandlers(application, options = {}) {
|
|
|
119
120
|
function managedServerResource(config) {
|
|
120
121
|
let shutdownPromise;
|
|
121
122
|
const getServer = () => typeof config.server === "function" ? config.server() : config.server;
|
|
123
|
+
const whole = (milliseconds, round) => Number.isFinite(milliseconds) ? Math.max(0, round(milliseconds)) : milliseconds;
|
|
124
|
+
const grace = (milliseconds) => whole(milliseconds, Math.floor);
|
|
125
|
+
const force = (milliseconds) => whole(milliseconds, Math.ceil);
|
|
122
126
|
const ensureShutdown = (context, phase = "graceful") => {
|
|
123
127
|
if (shutdownPromise)
|
|
124
128
|
return shutdownPromise;
|
|
125
129
|
const now = context.now();
|
|
126
|
-
const gracePeriodMs = phase === "force" ? 0 :
|
|
127
|
-
const forceTimeoutMs = phase === "force" ?
|
|
130
|
+
const gracePeriodMs = phase === "force" ? 0 : context.deadlineAt === undefined ? undefined : grace(context.deadlineAt - now);
|
|
131
|
+
const forceTimeoutMs = context.forceDeadlineAt === undefined ? undefined : phase === "force" ? force(context.forceDeadlineAt - now) : force(context.forceDeadlineAt - (context.deadlineAt ?? now));
|
|
128
132
|
shutdownPromise = getServer().shutdown({
|
|
129
|
-
gracePeriodMs,
|
|
130
|
-
forceTimeoutMs,
|
|
131
|
-
retryAfterSeconds: config.retryAfterSeconds ?? 5,
|
|
133
|
+
...gracePeriodMs !== undefined && { gracePeriodMs },
|
|
134
|
+
...forceTimeoutMs !== undefined && { forceTimeoutMs },
|
|
135
|
+
retryAfterSeconds: grace(config.retryAfterSeconds ?? 5),
|
|
132
136
|
signal: context.signal
|
|
133
137
|
});
|
|
134
138
|
shutdownPromise.catch(() => {
|
|
@@ -171,6 +175,7 @@ export {
|
|
|
171
175
|
ApplicationLifecycleSchema,
|
|
172
176
|
ApplicationOperationalHandlersOptionsSchema,
|
|
173
177
|
ApplicationResourceShutdownSchema,
|
|
178
|
+
ApplicationShutdownBudgetSchema,
|
|
174
179
|
ApplicationShutdownOptionsSchema,
|
|
175
180
|
ApplicationShutdownResultSchema,
|
|
176
181
|
ApplicationSnapshotSchema,
|
|
@@ -25,6 +25,46 @@ import type { StitchLogger } from '../logger';
|
|
|
25
25
|
import type { RealtimeAcknowledgedEvent, RealtimeAcknowledgement, RealtimeContract, RealtimeEventRegistry, RealtimeRejectedEventHook, RealtimeRequestArguments } from '../realtime/contract';
|
|
26
26
|
import { type RealtimeRequestOptions } from '../realtime/request';
|
|
27
27
|
import { type ValidatedRealtimeSocket } from '../realtime/socket';
|
|
28
|
+
/**
|
|
29
|
+
* How this project loads the optional Socket.IO **client** peer.
|
|
30
|
+
*
|
|
31
|
+
* The mirror of `SocketIOPeerLoaders` on the server, and for the same reason.
|
|
32
|
+
* The specifier above is a variable, so no bundler can follow it — by
|
|
33
|
+
* construction, not by accident. A consumer who ships one self-contained file
|
|
34
|
+
* to a machine with no `node_modules` therefore had no way to get
|
|
35
|
+
* `socket.io-client` into the artifact, and learned about it at the first
|
|
36
|
+
* `connect()` rather than at build time. The only workaround was patching
|
|
37
|
+
* stitchkit's built `dist`, which breaks whenever its internal layout moves —
|
|
38
|
+
* exactly the dead end the server half was added to close.
|
|
39
|
+
*
|
|
40
|
+
* Passing a loader puts the literal in the CONSUMER's source, where their own
|
|
41
|
+
* bundler sees it statically and includes the package:
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* createSocketIOClient({
|
|
45
|
+
* url,
|
|
46
|
+
* peers: { client: () => import('socket.io-client') },
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* A function rather than an already-resolved module, so laziness is unchanged:
|
|
51
|
+
* a project that never opens a socket still never loads it.
|
|
52
|
+
*/
|
|
53
|
+
export interface SocketIOClientPeerLoaders {
|
|
54
|
+
/**
|
|
55
|
+
* `() => import('socket.io-client')`.
|
|
56
|
+
*
|
|
57
|
+
* Typed as `unknown` and shape-checked where it is used — the same reason
|
|
58
|
+
* `SocketIOPeerLoaders.bunEngine` is. The root `stitchkit` entry is the
|
|
59
|
+
* browser-safe one, and its declarations must not name `socket.io-client`:
|
|
60
|
+
* a consumer who imports `createClient` and never opens a socket would then
|
|
61
|
+
* need the package installed just to TYPECHECK, which the consumer-lane peer
|
|
62
|
+
* budget refuses by name. The loader is still written the obvious way; only
|
|
63
|
+
* the type of what it returns is checked at the boundary rather than here,
|
|
64
|
+
* and a loader that returns the wrong module is refused by name at runtime.
|
|
65
|
+
*/
|
|
66
|
+
client?: () => Promise<unknown>;
|
|
67
|
+
}
|
|
28
68
|
/**
|
|
29
69
|
* Socket.IO event map — `{ event: (...args) => void }`. Aliases Socket.IO's
|
|
30
70
|
* own `EventsMap` constraint, which intentionally maps to `any`: that is what
|
|
@@ -120,6 +160,13 @@ export interface SocketIOClientConfig<TServerEvents extends SocketEventMap = Soc
|
|
|
120
160
|
event: string;
|
|
121
161
|
args: unknown[];
|
|
122
162
|
}) => void;
|
|
163
|
+
/**
|
|
164
|
+
* How to load the optional `socket.io-client` peer. Omit it and the peer is
|
|
165
|
+
* resolved lazily, exactly as before — this exists for a consumer who ships
|
|
166
|
+
* one self-contained artifact and needs the specifier to be a literal their
|
|
167
|
+
* own bundler can follow. → `SocketIOClientPeerLoaders`
|
|
168
|
+
*/
|
|
169
|
+
peers?: SocketIOClientPeerLoaders;
|
|
123
170
|
}
|
|
124
171
|
export interface SocketIOClient<TServerEvents extends SocketEventMap, TClientEvents extends SocketEventMap> {
|
|
125
172
|
/** Create the socket (if absent) and connect. Idempotent. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/browser/socket-io.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"socket-io.d.ts","sourceRoot":"","sources":["../../src/browser/socket-io.ts"],"names":[],"mappings":"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"}
|
package/dist/browser/stream.d.ts
CHANGED
|
@@ -1,2 +1,25 @@
|
|
|
1
1
|
export { type ParseSSEOptions, parseSSE } from '../server/stream';
|
|
2
|
+
/** Options for `parseNDJSON`. */
|
|
3
|
+
export interface ParseNDJSONOptions {
|
|
4
|
+
/** Called for a line that is not valid JSON — the alternative to throwing. */
|
|
5
|
+
onParseError?: (raw: string, error: Error) => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse a newline-delimited JSON response body — the client half of
|
|
9
|
+
* `ndjsonRoute`.
|
|
10
|
+
*
|
|
11
|
+
* **Blank lines are skipped**, and that is the contract rather than a
|
|
12
|
+
* convenience. A long-lived NDJSON stream has to send something while it is
|
|
13
|
+
* idle or intermediaries drop it, and the natural pulse for this framing is an
|
|
14
|
+
* empty line. Writing the skip down here is what stops it being a verbal
|
|
15
|
+
* agreement between the two halves of one project: the server's keep-alive and
|
|
16
|
+
* the reader's rule are one decision with two implementations.
|
|
17
|
+
*
|
|
18
|
+
* **To end a subscription, abort the request.** Leaving the loop cancels the
|
|
19
|
+
* body — which is right, and this does it — but a client-side cancel is not a
|
|
20
|
+
* reliable way to reach the server: measured against Bun today, the source on
|
|
21
|
+
* the other end stayed alive for seconds afterwards. An aborted request reaches
|
|
22
|
+
* the route's `context.signal` at once.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseNDJSON<T>(response: Response, options?: ParseNDJSONOptions): AsyncGenerator<T>;
|
|
2
25
|
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/browser/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/browser/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAElE,iCAAiC;AACjC,MAAM,WAAW,kBAAkB;IACjC,8EAA8E;IAC9E,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAuB,WAAW,CAAC,CAAC,EAClC,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,cAAc,CAAC,CAAC,CAAC,CAmDnB"}
|
package/dist/contract/index.js
CHANGED
|
@@ -427,4 +427,4 @@ function decodeCursor(cursor, schema) {
|
|
|
427
427
|
return null;
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
|
-
export { parseTrailingWildcard, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError,
|
|
430
|
+
export { parseTrailingWildcard, ALL_TRANSPORTS, defineContract, AppError, notFound, badRequest, unauthorized, forbidden, conflict, rateLimited, STITCH_ERROR_STATUS, isStitchErrorCode, appError, defineErrors, createContractFactory, ManagedFilePathSchema, ManagedFileRefSchema, paginatedSchema, encodeCursor, decodeCursor };
|
|
@@ -75,6 +75,10 @@ var ApplicationShutdownOptionsSchema = ShutdownOptionsSchema.pick({
|
|
|
75
75
|
forceTimeoutMs: true,
|
|
76
76
|
signal: true
|
|
77
77
|
});
|
|
78
|
+
var ApplicationShutdownBudgetSchema = ShutdownOptionsSchema.pick({
|
|
79
|
+
gracePeriodMs: true,
|
|
80
|
+
forceTimeoutMs: true
|
|
81
|
+
});
|
|
78
82
|
|
|
79
83
|
class ApplicationAdmissionError extends AppError {
|
|
80
84
|
constructor() {
|
|
@@ -100,6 +104,7 @@ async function untilDeadline(work, signal) {
|
|
|
100
104
|
function createApplication(config) {
|
|
101
105
|
const id = ApplicationIdSchema.parse(config.id);
|
|
102
106
|
const ordered = resolveResourceGraph(config.resources ?? []);
|
|
107
|
+
const shutdownBudget = ApplicationShutdownBudgetSchema.parse(config.shutdown ?? {});
|
|
103
108
|
const reverse = [...ordered].reverse();
|
|
104
109
|
const reportFailure = (resourceId, phase, error) => {
|
|
105
110
|
if (!config.onResourceFailure)
|
|
@@ -116,6 +121,8 @@ function createApplication(config) {
|
|
|
116
121
|
entry,
|
|
117
122
|
state: "registered",
|
|
118
123
|
health: "unknown",
|
|
124
|
+
healthReported: false,
|
|
125
|
+
everHealthy: false,
|
|
119
126
|
attempted: false,
|
|
120
127
|
activated: false,
|
|
121
128
|
closeInvoked: false,
|
|
@@ -203,6 +210,9 @@ function createApplication(config) {
|
|
|
203
210
|
if (record.state === "stopped")
|
|
204
211
|
return;
|
|
205
212
|
record.health = health;
|
|
213
|
+
record.healthReported = true;
|
|
214
|
+
if (health === "healthy")
|
|
215
|
+
record.everHealthy = true;
|
|
206
216
|
accepting = activationComplete && !shutdownRequested && isReady();
|
|
207
217
|
publish();
|
|
208
218
|
}
|
|
@@ -221,6 +231,22 @@ function createApplication(config) {
|
|
|
221
231
|
};
|
|
222
232
|
const closeAttempted = async () => {
|
|
223
233
|
const errors = [];
|
|
234
|
+
const rollbackStartedAt = performance.now();
|
|
235
|
+
const rollbackDeadlineAt = rollbackStartedAt + shutdownBudget.gracePeriodMs;
|
|
236
|
+
const rollbackForceDeadlineAt = rollbackDeadlineAt + shutdownBudget.forceTimeoutMs;
|
|
237
|
+
const rollbackAbort = new AbortController;
|
|
238
|
+
const rollbackTimer = setTimeout(() => rollbackAbort.abort(), Math.max(0, rollbackForceDeadlineAt - performance.now()));
|
|
239
|
+
try {
|
|
240
|
+
await closeEachAttempted(rollbackAbort.signal, errors, {
|
|
241
|
+
deadlineAt: rollbackDeadlineAt,
|
|
242
|
+
forceDeadlineAt: rollbackForceDeadlineAt
|
|
243
|
+
});
|
|
244
|
+
} finally {
|
|
245
|
+
clearTimeout(rollbackTimer);
|
|
246
|
+
}
|
|
247
|
+
return errors;
|
|
248
|
+
};
|
|
249
|
+
const closeEachAttempted = async (bound, errors, deadlines) => {
|
|
224
250
|
for (const entry of reverse) {
|
|
225
251
|
const record = records.get(entry.id);
|
|
226
252
|
if (!record?.attempted || record.closed)
|
|
@@ -228,7 +254,18 @@ function createApplication(config) {
|
|
|
228
254
|
record.state = "stopping";
|
|
229
255
|
try {
|
|
230
256
|
record.closeInvoked = true;
|
|
231
|
-
await entry.resource.close?.(contextFor(record, { signal: startupAbort.signal }));
|
|
257
|
+
const settled = await untilDeadline(Promise.resolve(entry.resource.close?.(contextFor(record, { signal: startupAbort.signal, ...deadlines }))), bound);
|
|
258
|
+
if (!settled.settled) {
|
|
259
|
+
record.failures.push("close");
|
|
260
|
+
record.state = "failed";
|
|
261
|
+
const timedOut = new Error(`[stitchkit] resource "${entry.id}" did not finish closing during rollback`);
|
|
262
|
+
reportFailure(entry.id, "close", timedOut);
|
|
263
|
+
errors.push(timedOut);
|
|
264
|
+
publish();
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
if (settled.error !== undefined)
|
|
268
|
+
throw settled.error;
|
|
232
269
|
record.closed = true;
|
|
233
270
|
record.state = "stopped";
|
|
234
271
|
} catch (error) {
|
|
@@ -239,7 +276,6 @@ function createApplication(config) {
|
|
|
239
276
|
}
|
|
240
277
|
publish();
|
|
241
278
|
}
|
|
242
|
-
return errors;
|
|
243
279
|
};
|
|
244
280
|
const runStart = async () => {
|
|
245
281
|
lifecycle = "starting";
|
|
@@ -307,7 +343,10 @@ function createApplication(config) {
|
|
|
307
343
|
throw new ApplicationStartupInterruptedError;
|
|
308
344
|
}
|
|
309
345
|
record.state = "ready";
|
|
310
|
-
record.
|
|
346
|
+
if (!record.healthReported) {
|
|
347
|
+
record.health = "healthy";
|
|
348
|
+
record.everHealthy = true;
|
|
349
|
+
}
|
|
311
350
|
publish();
|
|
312
351
|
} catch (error) {
|
|
313
352
|
const interrupted = shutdownRequested || startupAbort.signal.aborted;
|
|
@@ -352,7 +391,8 @@ function createApplication(config) {
|
|
|
352
391
|
}
|
|
353
392
|
record.activated = true;
|
|
354
393
|
if (entry.required && (record.state !== "ready" || record.health !== "healthy")) {
|
|
355
|
-
|
|
394
|
+
const observed = `${record.state}/${record.health}`;
|
|
395
|
+
throw new Error(record.everHealthy ? `[stitchkit] required resource "${entry.id}" lost readiness during activation (${observed})` : `[stitchkit] required resource "${entry.id}" is not healthy (${observed}). A required resource must be healthy for the application to be ready; a resource that is expected to start degraded belongs behind \`required: false\`.`);
|
|
356
396
|
}
|
|
357
397
|
} catch (error) {
|
|
358
398
|
const interrupted = shutdownRequested || startupAbort.signal.aborted;
|
|
@@ -371,7 +411,11 @@ function createApplication(config) {
|
|
|
371
411
|
throw new ApplicationStartupInterruptedError;
|
|
372
412
|
}
|
|
373
413
|
if (!isReady()) {
|
|
374
|
-
|
|
414
|
+
const blocking = [...records.values()].filter((record) => record.entry.required && (record.state !== "ready" || record.health !== "healthy")).map((record) => `${record.entry.id} (${record.state}/${record.health})`);
|
|
415
|
+
if (blocking.length === 0)
|
|
416
|
+
blocking.push("(none identified)");
|
|
417
|
+
const chosen = [...records.values()].some((record) => record.entry.required && record.health !== "healthy" && !record.everHealthy);
|
|
418
|
+
throw new Error(`[stitchkit] the application is not ready after startup — required ${blocking.length === 1 ? "resource" : "resources"} ${blocking.join(", ")}. A required resource must be healthy for the application to be ready; ${chosen ? "a resource that is expected to start degraded belongs behind `required: false`." : "this one was healthy and stopped being so — read `onResourceFailure` for the cause."}`);
|
|
375
419
|
}
|
|
376
420
|
activationComplete = true;
|
|
377
421
|
accepting = isReady();
|
|
@@ -447,7 +491,12 @@ function createApplication(config) {
|
|
|
447
491
|
const shutdown = (options) => {
|
|
448
492
|
if (shutdownPromise)
|
|
449
493
|
return shutdownPromise;
|
|
450
|
-
const
|
|
494
|
+
const requested = options ?? {};
|
|
495
|
+
const parsed = ApplicationShutdownOptionsSchema.parse({
|
|
496
|
+
gracePeriodMs: requested.gracePeriodMs ?? shutdownBudget.gracePeriodMs,
|
|
497
|
+
forceTimeoutMs: requested.forceTimeoutMs ?? shutdownBudget.forceTimeoutMs,
|
|
498
|
+
...requested.signal !== undefined && { signal: requested.signal }
|
|
499
|
+
});
|
|
451
500
|
const startedAt = performance.now();
|
|
452
501
|
const graceDeadlineAt = startedAt + parsed.gracePeriodMs;
|
|
453
502
|
const forceDeadlineAt = graceDeadlineAt + parsed.forceTimeoutMs;
|
|
@@ -650,4 +699,4 @@ function createApplication(config) {
|
|
|
650
699
|
};
|
|
651
700
|
}
|
|
652
701
|
|
|
653
|
-
export { ApplicationShutdownOptionsSchema, ApplicationAdmissionError, createApplication };
|
|
702
|
+
export { ApplicationShutdownOptionsSchema, ApplicationShutdownBudgetSchema, ApplicationAdmissionError, createApplication };
|
|
@@ -1563,6 +1563,46 @@ function bindProcessSignals(handle, options = {}) {
|
|
|
1563
1563
|
return { promise, close };
|
|
1564
1564
|
}
|
|
1565
1565
|
|
|
1566
|
+
// src/realtime/rejected-frame.ts
|
|
1567
|
+
var REALTIME_REJECTION_KEY = "@stitchkit/realtime-rejected";
|
|
1568
|
+
var MAX_REJECTION_ISSUES = 20;
|
|
1569
|
+
function realtimeRejectionEnvelope(report) {
|
|
1570
|
+
return { [REALTIME_REJECTION_KEY]: report };
|
|
1571
|
+
}
|
|
1572
|
+
function asRealtimeRejection(value) {
|
|
1573
|
+
if (typeof value !== "object" || value === null)
|
|
1574
|
+
return null;
|
|
1575
|
+
const report = Reflect.get(value, REALTIME_REJECTION_KEY);
|
|
1576
|
+
if (typeof report !== "object" || report === null)
|
|
1577
|
+
return null;
|
|
1578
|
+
const event = Reflect.get(report, "event");
|
|
1579
|
+
const reason = Reflect.get(report, "reason");
|
|
1580
|
+
const message = Reflect.get(report, "message");
|
|
1581
|
+
if (typeof event !== "string" || typeof reason !== "string" || typeof message !== "string") {
|
|
1582
|
+
return null;
|
|
1583
|
+
}
|
|
1584
|
+
if (reason.length === 0)
|
|
1585
|
+
return null;
|
|
1586
|
+
const issues = parseIssues(Reflect.get(report, "issues"));
|
|
1587
|
+
return { event, reason, message, ...issues !== undefined && { issues } };
|
|
1588
|
+
}
|
|
1589
|
+
function parseIssues(value) {
|
|
1590
|
+
if (!Array.isArray(value))
|
|
1591
|
+
return;
|
|
1592
|
+
const issues = [];
|
|
1593
|
+
for (const entry of value.slice(0, MAX_REJECTION_ISSUES)) {
|
|
1594
|
+
if (typeof entry !== "object" || entry === null)
|
|
1595
|
+
continue;
|
|
1596
|
+
const path = Reflect.get(entry, "path");
|
|
1597
|
+
const code = Reflect.get(entry, "code");
|
|
1598
|
+
const message = Reflect.get(entry, "message");
|
|
1599
|
+
if (typeof path === "string" && typeof code === "string" && typeof message === "string") {
|
|
1600
|
+
issues.push({ path, code, message });
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
return issues.length > 0 ? issues : undefined;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1566
1606
|
// src/realtime/rejection.ts
|
|
1567
1607
|
import { z } from "zod";
|
|
1568
1608
|
function realtimeContractViolation(options) {
|
|
@@ -1590,15 +1630,11 @@ function method(target, name) {
|
|
|
1590
1630
|
return (...args) => Reflect.apply(value, target, args);
|
|
1591
1631
|
}
|
|
1592
1632
|
function splitWireArguments(definition, args) {
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
return {
|
|
1599
|
-
values: args.slice(0, -1),
|
|
1600
|
-
acknowledgement: (...callbackArgs) => Reflect.apply(acknowledgement, undefined, callbackArgs)
|
|
1601
|
-
};
|
|
1633
|
+
const trailing = args.at(-1);
|
|
1634
|
+
const replyTo = typeof trailing === "function" ? (...callbackArgs) => Reflect.apply(trailing, undefined, callbackArgs) : undefined;
|
|
1635
|
+
if (!definition.ack || !replyTo)
|
|
1636
|
+
return { values: args, ...replyTo && { replyTo } };
|
|
1637
|
+
return { values: args.slice(0, -1), acknowledgement: replyTo, replyTo };
|
|
1602
1638
|
}
|
|
1603
1639
|
function eventDefinition(registry, event, direction) {
|
|
1604
1640
|
const definition = registry[event];
|
|
@@ -1626,6 +1662,19 @@ function reportRejected(rejected, hook, logger) {
|
|
|
1626
1662
|
console.error("[stitchkit] realtime rejection hook failed", error);
|
|
1627
1663
|
});
|
|
1628
1664
|
}
|
|
1665
|
+
function answerWithRejection(acknowledgement, report, logger) {
|
|
1666
|
+
if (!acknowledgement)
|
|
1667
|
+
return;
|
|
1668
|
+
try {
|
|
1669
|
+
acknowledgement(realtimeRejectionEnvelope(report));
|
|
1670
|
+
} catch (error) {
|
|
1671
|
+
const message = "[stitchkit] could not answer a rejected realtime frame";
|
|
1672
|
+
if (logger)
|
|
1673
|
+
logger.warn(message, { error });
|
|
1674
|
+
else
|
|
1675
|
+
console.warn(message, error);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1629
1678
|
function createValidatedRealtimeSocket({
|
|
1630
1679
|
target,
|
|
1631
1680
|
inbound,
|
|
@@ -1641,17 +1690,24 @@ function createValidatedRealtimeSocket({
|
|
|
1641
1690
|
on: (event, handler) => {
|
|
1642
1691
|
const definition = eventDefinition(inbound, event, inboundDirection);
|
|
1643
1692
|
const wrapped = (...wireArgs) => {
|
|
1644
|
-
const { values, acknowledgement } = splitWireArguments(definition, wireArgs);
|
|
1693
|
+
const { values, acknowledgement, replyTo } = splitWireArguments(definition, wireArgs);
|
|
1645
1694
|
const parsed = definition.args.safeParse(values);
|
|
1646
1695
|
if (!parsed.success) {
|
|
1647
|
-
|
|
1696
|
+
const rejected = realtimeContractViolation({
|
|
1648
1697
|
event,
|
|
1649
1698
|
direction: inboundDirection,
|
|
1650
1699
|
phase: "arguments",
|
|
1651
1700
|
reason: "invalid-arguments",
|
|
1652
1701
|
fault: "peer",
|
|
1653
1702
|
cause: parsed.error
|
|
1654
|
-
})
|
|
1703
|
+
});
|
|
1704
|
+
reportRejected(rejected, onRejected, logger);
|
|
1705
|
+
answerWithRejection(replyTo, {
|
|
1706
|
+
event,
|
|
1707
|
+
reason: "invalid-arguments",
|
|
1708
|
+
message: rejected.error.message,
|
|
1709
|
+
issues: zodIssues(parsed.error).slice(0, MAX_REJECTION_ISSUES)
|
|
1710
|
+
}, logger);
|
|
1655
1711
|
return;
|
|
1656
1712
|
}
|
|
1657
1713
|
if (definition.ack && !acknowledgement) {
|
|
@@ -1721,6 +1777,17 @@ function createValidatedRealtimeSocket({
|
|
|
1721
1777
|
const wireArgs = [...parsed.data];
|
|
1722
1778
|
if (definition.ack && acknowledgement) {
|
|
1723
1779
|
wireArgs.push((value) => {
|
|
1780
|
+
const refusal = asRealtimeRejection(value);
|
|
1781
|
+
if (refusal) {
|
|
1782
|
+
reportRejected(realtimeContractViolation({
|
|
1783
|
+
event,
|
|
1784
|
+
direction: outboundDirection,
|
|
1785
|
+
phase: "arguments",
|
|
1786
|
+
reason: "rejected-by-peer",
|
|
1787
|
+
fault: "local"
|
|
1788
|
+
}), onRejected, logger);
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1724
1791
|
const ack = definition.ack?.safeParse(value);
|
|
1725
1792
|
if (!ack?.success) {
|
|
1726
1793
|
if (ack) {
|
|
@@ -1841,17 +1908,19 @@ function composeWebSocketHandlers(lanes, config) {
|
|
|
1841
1908
|
};
|
|
1842
1909
|
}
|
|
1843
1910
|
|
|
1911
|
+
// src/internal/optional-peer.ts
|
|
1912
|
+
function isModuleNotFound(error) {
|
|
1913
|
+
if (typeof error !== "object" || error === null)
|
|
1914
|
+
return false;
|
|
1915
|
+
const code = "code" in error ? error.code : undefined;
|
|
1916
|
+
const message = "message" in error && typeof error.message === "string" ? error.message : "";
|
|
1917
|
+
return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND" || message.includes("Cannot find module") || message.includes("Cannot find package");
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1844
1920
|
// src/server/socket-io.ts
|
|
1845
1921
|
var SOCKET_IO_SERVER = "socket.io";
|
|
1846
1922
|
var SOCKET_IO_BUN_ENGINE = "@socket.io/bun-engine";
|
|
1847
1923
|
var noop = () => {};
|
|
1848
|
-
function isModuleNotFound(err) {
|
|
1849
|
-
if (typeof err !== "object" || err === null)
|
|
1850
|
-
return false;
|
|
1851
|
-
const code = "code" in err ? err.code : undefined;
|
|
1852
|
-
const message = "message" in err && typeof err.message === "string" ? err.message : "";
|
|
1853
|
-
return code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND" || message.includes("Cannot find module") || message.includes("Cannot find package");
|
|
1854
|
-
}
|
|
1855
1924
|
async function importPeer(load, pkg, injected) {
|
|
1856
1925
|
try {
|
|
1857
1926
|
return await load();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { type ClientConfig, type ClientContract, type ClientFetch, type ClientRegistryValue, type ContractClientConfig, contractEndpointMatchers, createClient, createClients, createScopedClients, createScopedUrlBuilders, createUrlBuilder, createUrlBuilders, type PathPrefixArgs, type RegistryScope, type ScopeClientConfigs, type ScopedClientRegistry, type ScopedUrlBuilderRegistry, type UrlBuilderConfig, } from './browser/client';
|
|
2
2
|
export { ApiError, type ApiEvent, type ApiEventListener, type ConfiguredHttpClient, createHttpClient, type HeaderProvider, type HttpClient, type HttpClientConfig, type RequestOptions, type UnauthorizedMatcher, } from './browser/http';
|
|
3
|
-
export type { BindRealtimeClientOptions, BoundRealtimeClient, RealtimeClient, RealtimeClientOptions, RealtimeClientTransport, SocketEventMap, SocketIOClient, SocketIOClientConfig, } from './browser/socket-io';
|
|
3
|
+
export type { BindRealtimeClientOptions, BoundRealtimeClient, RealtimeClient, RealtimeClientOptions, RealtimeClientTransport, SocketEventMap, SocketIOClient, SocketIOClientConfig, SocketIOClientPeerLoaders, } from './browser/socket-io';
|
|
4
4
|
export { bindRealtimeClient, createRealtimeClient, createSocketIOClient, } from './browser/socket-io';
|
|
5
|
-
export { type ParseSSEOptions, parseSSE } from './browser/stream';
|
|
5
|
+
export { type ParseNDJSONOptions, type ParseSSEOptions, parseNDJSON, parseSSE, } from './browser/stream';
|
|
6
6
|
export * from './contract';
|
|
7
7
|
export type { StitchLogger } from './logger';
|
|
8
8
|
export { childSpan, createTraceContext, formatTraceparent, parseTraceparent, type TraceContext, } from './observability/trace';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,wBAAwB,EACxB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,wBAAwB,EACxB,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,QAAQ,EACR,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,gBAAgB,EAChB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,cAAc,EACd,cAAc,EACd,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,WAAW,EACX,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAG7C,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC"}
|