@qlever-llc/trellis 0.10.12 → 0.10.14

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 (101) hide show
  1. package/esm/auth/browser.js +0 -1
  2. package/esm/auth.js +0 -1
  3. package/esm/browser.d.ts +29 -2
  4. package/esm/browser.d.ts.map +1 -1
  5. package/esm/browser.js +14 -3
  6. package/esm/client_connect.d.ts.map +1 -1
  7. package/esm/client_connect.js +7 -3
  8. package/esm/contract_support/mod.d.ts +6 -10
  9. package/esm/contract_support/mod.d.ts.map +1 -1
  10. package/esm/contract_support/mod.js +42 -31
  11. package/esm/contract_support/protocol.d.ts +8 -13
  12. package/esm/contract_support/protocol.d.ts.map +1 -1
  13. package/esm/contract_support/protocol.js +4 -5
  14. package/esm/contract_support/schema_pointers.d.ts +6 -0
  15. package/esm/contract_support/schema_pointers.d.ts.map +1 -1
  16. package/esm/contract_support/schema_pointers.js +59 -7
  17. package/esm/contracts.js +0 -1
  18. package/esm/device.d.ts +0 -29
  19. package/esm/device.d.ts.map +1 -1
  20. package/esm/device.js +10 -1
  21. package/esm/errors/index.js +0 -1
  22. package/esm/index.d.ts +3 -4
  23. package/esm/index.d.ts.map +1 -1
  24. package/esm/index.js +3 -4
  25. package/esm/runtime_transport.d.ts.map +1 -1
  26. package/esm/runtime_transport.js +4 -2
  27. package/esm/server/health_rpc.d.ts +4 -2
  28. package/esm/server/health_rpc.d.ts.map +1 -1
  29. package/esm/server/health_rpc.js +6 -1
  30. package/esm/server/service.d.ts +12 -37
  31. package/esm/server/service.d.ts.map +1 -1
  32. package/esm/server/service.js +138 -103
  33. package/esm/server.js +3 -3
  34. package/esm/service/outbox_inbox.d.ts +1 -6
  35. package/esm/service/outbox_inbox.d.ts.map +1 -1
  36. package/esm/service/outbox_inbox.js +0 -21
  37. package/esm/telemetry/env.d.ts.map +1 -1
  38. package/esm/telemetry/env.js +5 -6
  39. package/esm/telemetry/metrics.d.ts +0 -7
  40. package/esm/telemetry/metrics.d.ts.map +1 -1
  41. package/esm/trellis.d.ts +1 -19
  42. package/esm/trellis.d.ts.map +1 -1
  43. package/esm/trellis.js +12 -8
  44. package/package.json +2 -2
  45. package/script/auth/browser.js +0 -1
  46. package/script/auth.js +0 -1
  47. package/script/browser.d.ts +29 -2
  48. package/script/browser.d.ts.map +1 -1
  49. package/script/browser.js +75 -17
  50. package/script/client_connect.d.ts.map +1 -1
  51. package/script/client_connect.js +7 -36
  52. package/script/contract_support/mod.d.ts +6 -10
  53. package/script/contract_support/mod.d.ts.map +1 -1
  54. package/script/contract_support/mod.js +46 -32
  55. package/script/contract_support/protocol.d.ts +8 -13
  56. package/script/contract_support/protocol.d.ts.map +1 -1
  57. package/script/contract_support/protocol.js +5 -6
  58. package/script/contract_support/schema_pointers.d.ts +6 -0
  59. package/script/contract_support/schema_pointers.d.ts.map +1 -1
  60. package/script/contract_support/schema_pointers.js +59 -7
  61. package/script/contracts.js +0 -1
  62. package/script/device.d.ts +0 -29
  63. package/script/device.d.ts.map +1 -1
  64. package/script/device.js +10 -1
  65. package/script/errors/index.js +0 -1
  66. package/script/index.d.ts +3 -4
  67. package/script/index.d.ts.map +1 -1
  68. package/script/index.js +1 -6
  69. package/script/runtime_transport.d.ts.map +1 -1
  70. package/script/runtime_transport.js +4 -2
  71. package/script/server/health_rpc.d.ts +4 -2
  72. package/script/server/health_rpc.d.ts.map +1 -1
  73. package/script/server/health_rpc.js +6 -1
  74. package/script/server/service.d.ts +12 -37
  75. package/script/server/service.d.ts.map +1 -1
  76. package/script/server/service.js +148 -112
  77. package/script/server.js +3 -3
  78. package/script/service/outbox_inbox.d.ts +1 -6
  79. package/script/service/outbox_inbox.d.ts.map +1 -1
  80. package/script/service/outbox_inbox.js +0 -21
  81. package/script/telemetry/env.d.ts.map +1 -1
  82. package/script/telemetry/env.js +5 -39
  83. package/script/telemetry/metrics.d.ts +0 -7
  84. package/script/telemetry/metrics.d.ts.map +1 -1
  85. package/script/trellis.d.ts +1 -19
  86. package/script/trellis.d.ts.map +1 -1
  87. package/script/trellis.js +12 -8
  88. package/src/browser.ts +200 -2
  89. package/src/client_connect.ts +10 -2
  90. package/src/contract_support/mod.ts +73 -45
  91. package/src/contract_support/protocol.ts +16 -7
  92. package/src/contract_support/schema_pointers.ts +80 -7
  93. package/src/device.ts +10 -2
  94. package/src/index.ts +3 -4
  95. package/src/runtime_transport.ts +6 -1
  96. package/src/server/health_rpc.ts +7 -2
  97. package/src/server/service.ts +177 -126
  98. package/src/server.ts +3 -3
  99. package/src/service/outbox_inbox.ts +1 -28
  100. package/src/telemetry/env.ts +10 -7
  101. package/src/trellis.ts +22 -13
@@ -57,7 +57,6 @@ import {
57
57
  type SubjectParam,
58
58
  } from "./schema_pointers.js";
59
59
  import {
60
- type ContractEventConsumerEvent,
61
60
  type ContractEventConsumerGroup,
62
61
  type ContractEventConsumers,
63
62
  ContractEventConsumersSchema,
@@ -70,12 +69,14 @@ import {
70
69
  export {
71
70
  buildCursorPage,
72
71
  buildPageResponse,
73
- type ContractEventConsumerEvent,
74
- ContractEventConsumerEventSchema,
75
72
  type ContractEventConsumerGroup,
76
73
  ContractEventConsumerGroupSchema,
77
74
  type ContractEventConsumers,
75
+ type ContractEventConsumerSelf,
76
+ ContractEventConsumerSelfSchema,
78
77
  ContractEventConsumersSchema,
78
+ type ContractEventConsumerUses,
79
+ ContractEventConsumerUsesSchema,
79
80
  ContractJobQueueSchema,
80
81
  ContractJobsSchema,
81
82
  ContractKvResourceSchema,
@@ -115,6 +116,10 @@ export {
115
116
  type StoreResourceBinding,
116
117
  StoreResourceBindingSchema,
117
118
  } from "./protocol.js";
119
+ export {
120
+ assertDataPointersExistAndAreTokenable,
121
+ getSubschemaAtDataPointer,
122
+ } from "./schema_pointers.js";
118
123
 
119
124
  export const CONTRACT_FORMAT_V1 = "trellis.contract.v1" as const;
120
125
  export const CATALOG_FORMAT_V1 = "trellis.catalog.v1" as const;
@@ -964,13 +969,9 @@ export type ContractSourceJobs<TSchemaName extends string = string> = Record<
964
969
  ContractSourceJobQueue<TSchemaName>
965
970
  >;
966
971
 
967
- export type ContractSourceEventConsumerEvent = {
968
- use: string;
969
- event: string;
970
- };
971
-
972
972
  export type ContractSourceEventConsumerGroup = {
973
- events: readonly ContractSourceEventConsumerEvent[];
973
+ uses?: Record<string, readonly string[]>;
974
+ self?: readonly string[];
974
975
  replay?: "new" | "all";
975
976
  ordering?: "strict";
976
977
  concurrency?: number;
@@ -2637,7 +2638,9 @@ function projectDigestJobs(
2637
2638
  function projectDigestEventConsumers(
2638
2639
  eventConsumers: ContractEventConsumers | undefined,
2639
2640
  ): ContractEventConsumers | undefined {
2640
- return eventConsumers ? mapValues(eventConsumers, omitDocs) : undefined;
2641
+ return eventConsumers
2642
+ ? mapValues(eventConsumers, projectDigestEventConsumerGroup)
2643
+ : undefined;
2641
2644
  }
2642
2645
 
2643
2646
  function projectDigestUsesFlat(
@@ -3068,25 +3071,31 @@ function feed(feed: ContractFeed): ContractFeed {
3068
3071
  };
3069
3072
  }
3070
3073
 
3071
- function eventConsumerEvent(
3072
- event: ContractEventConsumerEvent,
3073
- ): ContractEventConsumerEvent {
3074
- return { use: event.use, event: event.event };
3074
+ function sortEventConsumerUses(
3075
+ uses: Record<string, readonly string[]> | undefined,
3076
+ ): Record<string, string[]> | undefined {
3077
+ if (!uses) {
3078
+ return undefined;
3079
+ }
3080
+ return Object.fromEntries(
3081
+ Object.entries(uses)
3082
+ .sort(([left], [right]) => left.localeCompare(right))
3083
+ .map(([alias, events]) => [alias, sortedUnique(events)]),
3084
+ );
3075
3085
  }
3076
3086
 
3077
- function sortEventConsumerEvents(
3078
- events: readonly ContractEventConsumerEvent[],
3079
- ): ContractEventConsumerEvent[] {
3080
- return events.map(eventConsumerEvent).sort((left, right) =>
3081
- left.use.localeCompare(right.use) || left.event.localeCompare(right.event)
3082
- );
3087
+ function sortEventConsumerSelf(
3088
+ self: readonly string[] | undefined,
3089
+ ): string[] | undefined {
3090
+ return self ? sortedUnique(self) : undefined;
3083
3091
  }
3084
3092
 
3085
3093
  function eventConsumerGroup(
3086
- group: ContractEventConsumerGroup,
3094
+ group: ContractSourceEventConsumerGroup,
3087
3095
  ): ContractEventConsumerGroup {
3088
3096
  return {
3089
- events: sortEventConsumerEvents(group.events),
3097
+ ...(group.uses ? { uses: sortEventConsumerUses(group.uses) } : {}),
3098
+ ...(group.self ? { self: sortEventConsumerSelf(group.self) } : {}),
3090
3099
  replay: group.replay ?? "new",
3091
3100
  ordering: group.ordering ?? "strict",
3092
3101
  concurrency: group.concurrency ?? 1,
@@ -3097,6 +3106,12 @@ function eventConsumerGroup(
3097
3106
  };
3098
3107
  }
3099
3108
 
3109
+ function projectDigestEventConsumerGroup(
3110
+ group: ContractEventConsumerGroup,
3111
+ ): ContractEventConsumerGroup {
3112
+ return omitDocs(eventConsumerGroup(group));
3113
+ }
3114
+
3100
3115
  function errorDecl(error: ContractErrorDecl): ContractErrorDecl {
3101
3116
  return {
3102
3117
  type: error.type,
@@ -3240,7 +3255,11 @@ export function parseContractManifest(value: unknown): TrellisContractV1 {
3240
3255
  );
3241
3256
  }
3242
3257
  const contract = normalizeContractManifest(parsed);
3243
- assertValidEventConsumers(contract.eventConsumers, contract.uses);
3258
+ assertValidEventConsumers(
3259
+ contract.eventConsumers,
3260
+ contract.uses,
3261
+ contract.events,
3262
+ );
3244
3263
  return contract;
3245
3264
  }
3246
3265
 
@@ -3408,20 +3427,7 @@ function emitEventConsumers(
3408
3427
  return Object.fromEntries(
3409
3428
  Object.entries(eventConsumers).map(([groupName, group]) => [
3410
3429
  groupName,
3411
- {
3412
- events: sortEventConsumerEvents(group.events),
3413
- replay: group.replay ?? "new",
3414
- ordering: group.ordering ?? "strict",
3415
- concurrency: group.concurrency ?? 1,
3416
- ...(group.ackWaitMs !== undefined
3417
- ? { ackWaitMs: group.ackWaitMs }
3418
- : {}),
3419
- ...(group.maxDeliver !== undefined
3420
- ? { maxDeliver: group.maxDeliver }
3421
- : {}),
3422
- ...(group.backoffMs ? { backoffMs: [...group.backoffMs] } : {}),
3423
- ...(group.docs ? { docs: contractDocs(group.docs) } : {}),
3424
- } satisfies ContractEventConsumerGroup,
3430
+ eventConsumerGroup(group),
3425
3431
  ]),
3426
3432
  );
3427
3433
  }
@@ -3840,7 +3846,7 @@ function emitContract(source: TrellisContractSource): TrellisContractV1 {
3840
3846
  const state = emitState(source.state);
3841
3847
  const resources = emitResources(source.resources);
3842
3848
  const uses = emitUses(source.uses);
3843
- assertValidEventConsumers(eventConsumers, uses);
3849
+ assertValidEventConsumers(eventConsumers, uses, events);
3844
3850
 
3845
3851
  return {
3846
3852
  format: CONTRACT_FORMAT_V1,
@@ -4151,15 +4157,20 @@ function contractUseByAlias(
4151
4157
  function assertValidEventConsumers(
4152
4158
  eventConsumers: ContractEventConsumers | undefined,
4153
4159
  uses: ContractUses | undefined,
4160
+ ownedEvents: Record<string, ContractEvent> | undefined,
4154
4161
  ): void {
4155
4162
  if (!eventConsumers) {
4156
4163
  return;
4157
4164
  }
4158
4165
 
4159
4166
  for (const [groupName, group] of Object.entries(eventConsumers)) {
4160
- if (group.events.length === 0) {
4167
+ const hasDependencyEvents = Object.values(group.uses ?? {}).some(
4168
+ (eventNames) => eventNames.length > 0,
4169
+ );
4170
+ const hasSelfEvents = (group.self?.length ?? 0) > 0;
4171
+ if (!hasDependencyEvents && !hasSelfEvents) {
4161
4172
  throw new Error(
4162
- `event consumer group '${groupName}' must declare events`,
4173
+ `event consumer group '${groupName}' must declare at least one dependency or self event`,
4163
4174
  );
4164
4175
  }
4165
4176
  if ((group.ordering ?? "strict") === "strict" && group.concurrency !== 1) {
@@ -4168,16 +4179,33 @@ function assertValidEventConsumers(
4168
4179
  );
4169
4180
  }
4170
4181
 
4171
- for (const eventRef of group.events) {
4172
- const use = contractUseByAlias(uses, eventRef.use);
4182
+ for (const [alias, eventNames] of Object.entries(group.uses ?? {})) {
4183
+ if (eventNames.length === 0) {
4184
+ throw new Error(
4185
+ `event consumer group '${groupName}' use '${alias}' must declare events`,
4186
+ );
4187
+ }
4188
+
4189
+ const use = contractUseByAlias(uses, alias);
4173
4190
  if (!use) {
4174
4191
  throw new Error(
4175
- `event consumer group '${groupName}' references unknown use '${eventRef.use}'`,
4192
+ `event consumer group '${groupName}' references unknown use '${alias}'`,
4176
4193
  );
4177
4194
  }
4178
- if (!use.events?.subscribe?.includes(eventRef.event)) {
4195
+
4196
+ for (const eventName of eventNames) {
4197
+ if (!use.events?.subscribe?.includes(eventName)) {
4198
+ throw new Error(
4199
+ `event consumer group '${groupName}' references event '${eventName}' that use '${alias}' does not subscribe to`,
4200
+ );
4201
+ }
4202
+ }
4203
+ }
4204
+
4205
+ for (const eventName of group.self ?? []) {
4206
+ if (!ownedEvents || !Object.hasOwn(ownedEvents, eventName)) {
4179
4207
  throw new Error(
4180
- `event consumer group '${groupName}' references event '${eventRef.event}' that use '${eventRef.use}' does not subscribe to`,
4208
+ `event consumer group '${groupName}' references unknown owned event '${eventName}'`,
4181
4209
  );
4182
4210
  }
4183
4211
  }
@@ -99,17 +99,26 @@ export const ContractJobsSchema = Type.Record(
99
99
 
100
100
  export type ContractJobs = Static<typeof ContractJobsSchema>;
101
101
 
102
- export const ContractEventConsumerEventSchema = Type.Object({
103
- use: Type.String({ minLength: 1 }),
104
- event: Type.String({ minLength: 1 }),
105
- });
102
+ export const ContractEventConsumerUsesSchema = Type.Record(
103
+ Type.String({ minLength: 1 }),
104
+ Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
105
+ );
106
+
107
+ export type ContractEventConsumerUses = Static<
108
+ typeof ContractEventConsumerUsesSchema
109
+ >;
110
+
111
+ export const ContractEventConsumerSelfSchema = Type.Array(
112
+ Type.String({ minLength: 1 }),
113
+ );
106
114
 
107
- export type ContractEventConsumerEvent = Static<
108
- typeof ContractEventConsumerEventSchema
115
+ export type ContractEventConsumerSelf = Static<
116
+ typeof ContractEventConsumerSelfSchema
109
117
  >;
110
118
 
111
119
  export const ContractEventConsumerGroupSchema = Type.Object({
112
- events: Type.Array(ContractEventConsumerEventSchema, { minItems: 1 }),
120
+ uses: Type.Optional(ContractEventConsumerUsesSchema),
121
+ self: Type.Optional(ContractEventConsumerSelfSchema),
113
122
  replay: Type.Optional(Type.Union([
114
123
  Type.Literal("new"),
115
124
  Type.Literal("all"),
@@ -62,7 +62,71 @@ function decodeJsonPointerSegment(segment: string): string {
62
62
  return segment.replaceAll("~1", "/").replaceAll("~0", "~");
63
63
  }
64
64
 
65
- function resolveSubschema(
65
+ type PointerResolution = {
66
+ found: boolean;
67
+ schemas: unknown[];
68
+ };
69
+
70
+ function pointerResolution(
71
+ found: boolean,
72
+ schemas: unknown[],
73
+ ): PointerResolution {
74
+ return { found, schemas };
75
+ }
76
+
77
+ function collectSubschemas(
78
+ schema: unknown,
79
+ segments: readonly string[],
80
+ ): PointerResolution {
81
+ if (segments.length === 0) return pointerResolution(true, [schema]);
82
+ if (!isJsonObject(schema)) return pointerResolution(false, []);
83
+
84
+ const resolved: unknown[] = [];
85
+ let found = false;
86
+
87
+ const properties = schema.properties;
88
+ const segment = segments[0];
89
+ if (
90
+ segment !== undefined && isJsonObject(properties) &&
91
+ Object.hasOwn(properties, segment)
92
+ ) {
93
+ const direct = collectSubschemas(properties[segment], segments.slice(1));
94
+ found = found || direct.found;
95
+ resolved.push(...direct.schemas);
96
+ }
97
+
98
+ const allOf = schema.allOf;
99
+ if (Array.isArray(allOf)) {
100
+ for (const branch of allOf) {
101
+ const branchResult = collectSubschemas(branch, segments);
102
+ found = found || branchResult.found;
103
+ resolved.push(...branchResult.schemas);
104
+ }
105
+ }
106
+
107
+ for (const key of ["anyOf", "oneOf"] as const) {
108
+ const variants = schema[key];
109
+ if (!Array.isArray(variants) || variants.length === 0) continue;
110
+
111
+ const variantSchemas: unknown[] = [];
112
+ let everyVariantResolved = true;
113
+ for (const variant of variants) {
114
+ const variantResult = collectSubschemas(variant, segments);
115
+ if (!variantResult.found) {
116
+ everyVariantResolved = false;
117
+ break;
118
+ }
119
+ variantSchemas.push(...variantResult.schemas);
120
+ }
121
+
122
+ if (everyVariantResolved) found = true;
123
+ resolved.push(...variantSchemas);
124
+ }
125
+
126
+ return pointerResolution(found, resolved);
127
+ }
128
+
129
+ function resolveFirstSubschema(
66
130
  schema: unknown,
67
131
  segments: readonly string[],
68
132
  ): unknown | undefined {
@@ -73,7 +137,7 @@ function resolveSubschema(
73
137
  const variants = schema[key];
74
138
  if (!Array.isArray(variants)) continue;
75
139
  for (const variant of variants) {
76
- const resolved = resolveSubschema(variant, segments);
140
+ const resolved = resolveFirstSubschema(variant, segments);
77
141
  if (resolved !== undefined) return resolved;
78
142
  }
79
143
  }
@@ -85,7 +149,7 @@ function resolveSubschema(
85
149
  if (!isJsonObject(properties) || !Object.hasOwn(properties, segment)) {
86
150
  return undefined;
87
151
  }
88
- return resolveSubschema(properties[segment], segments.slice(1));
152
+ return resolveFirstSubschema(properties[segment], segments.slice(1));
89
153
  }
90
154
 
91
155
  function isTokenableSchema(schema: unknown): boolean {
@@ -131,30 +195,39 @@ function isTokenableSchema(schema: unknown): boolean {
131
195
  return false;
132
196
  }
133
197
 
198
+ /**
199
+ * Returns the first schema node reachable by following a payload JSON Pointer.
200
+ */
134
201
  export function getSubschemaAtDataPointer(
135
202
  schema: unknown,
136
203
  pointer: string,
137
204
  ): unknown | undefined {
138
- return resolveSubschema(
205
+ return resolveFirstSubschema(
139
206
  schema,
140
207
  pointer.slice(1).split("/").map(decodeJsonPointerSegment),
141
208
  );
142
209
  }
143
210
 
211
+ /**
212
+ * Verifies that event subject parameter pointers resolve to tokenable schemas.
213
+ */
144
214
  export function assertDataPointersExistAndAreTokenable(
145
215
  name: string,
146
216
  schema: unknown,
147
217
  pointers: readonly string[],
148
218
  ): void {
149
219
  for (const pointer of pointers) {
150
- const node = getSubschemaAtDataPointer(schema, pointer);
151
- if (node === undefined) {
220
+ const resolved = collectSubschemas(
221
+ schema,
222
+ pointer.slice(1).split("/").map(decodeJsonPointerSegment),
223
+ );
224
+ if (!resolved.found) {
152
225
  throw new Error(
153
226
  `Invalid event subject param pointer '${pointer}' for event '${name}' (path not found in schema)`,
154
227
  );
155
228
  }
156
229
 
157
- if (!isTokenableSchema(node)) {
230
+ if (!resolved.schemas.every(isTokenableSchema)) {
158
231
  throw new Error(
159
232
  `Invalid event subject param pointer '${pointer}' for event '${name}' (must resolve to string/number schema)`,
160
233
  );
package/src/device.ts CHANGED
@@ -140,7 +140,6 @@ export type TrellisDeviceConnection<
140
140
  readonly stream: string;
141
141
  readonly api: TApi;
142
142
  readonly connection: TrellisConnection;
143
- readonly natsConnection: NatsConnection;
144
143
  readonly health: ServiceHealth;
145
144
  };
146
145
 
@@ -717,6 +716,9 @@ async function fetchDeviceBootstrap(args: {
717
716
  });
718
717
  }
719
718
 
719
+ /**
720
+ * @internal Exported for focused tests and platform-specific wrappers.
721
+ */
720
722
  export async function startDeviceActivationWithDeps<
721
723
  TContract extends DeviceContract<TrellisAPI, {
722
724
  state?: Readonly<Record<string, unknown>>;
@@ -758,6 +760,9 @@ export async function startDeviceActivationWithDeps<
758
760
  });
759
761
  }
760
762
 
763
+ /**
764
+ * @internal Exported for focused tests and platform-specific wrappers.
765
+ */
761
766
  export async function resumeDeviceActivationWithDeps<
762
767
  TLocalState extends TrellisDeviceLocalActivationState,
763
768
  TContract extends DeviceContract<TrellisAPI, {
@@ -783,6 +788,10 @@ export async function resumeDeviceActivationWithDeps<
783
788
  });
784
789
  }
785
790
 
791
+ /**
792
+ * @internal Exported for focused tests; applications should use
793
+ * `TrellisDevice.connect`.
794
+ */
786
795
  export async function connectDeviceWithDeps<
787
796
  TContract extends DeviceContract<TrellisAPI, {
788
797
  state?: Readonly<Record<string, unknown>>;
@@ -965,7 +974,6 @@ export async function connectDeviceWithDeps<
965
974
  stream: trellis.stream,
966
975
  api: trellis.api,
967
976
  connection: trellis.connection,
968
- natsConnection: trellis.natsConnection,
969
977
  health,
970
978
  };
971
979
  }
package/src/index.ts CHANGED
@@ -158,9 +158,9 @@ export type {
158
158
  TerminalJob,
159
159
  WorkerInfo,
160
160
  } from "./jobs.js";
161
- export { TypedKV, TypedKVEntry } from "./kv.js";
161
+ export { TypedKVEntry } from "./kv.js";
162
162
  export type { WatchEvent, WatchOptions } from "./kv.js";
163
- export { TypedStore, TypedStoreEntry } from "./store.js";
163
+ export { TypedStoreEntry } from "./store.js";
164
164
  export type {
165
165
  StoreBody,
166
166
  StoreInfo,
@@ -169,7 +169,7 @@ export type {
169
169
  StoreStatus,
170
170
  StoreWaitOptions,
171
171
  } from "./store.js";
172
- export { createTransferHandle, FileInfoSchema } from "./transfer.js";
172
+ export { FileInfoSchema } from "./transfer.js";
173
173
  export type {
174
174
  FileInfo,
175
175
  ReceiveTransferGrant,
@@ -249,5 +249,4 @@ export type {
249
249
  TrellisFor,
250
250
  ValueStateStoreClient,
251
251
  } from "./trellis.js";
252
- export { Trellis } from "./trellis.js";
253
252
  export type { TrellisDeviceConnection } from "./device.js";
@@ -29,6 +29,8 @@ export type RuntimeTransport = {
29
29
 
30
30
  type NativeGlobalThis = typeof dntShim.dntGlobalThis & {
31
31
  Deno?: { version?: { deno?: string } };
32
+ document?: unknown;
33
+ window?: unknown;
32
34
  };
33
35
 
34
36
  export function selectRuntimeTransportServers(
@@ -54,7 +56,10 @@ export function selectRuntimeTransportServers(
54
56
  }
55
57
 
56
58
  function isBrowserRuntime(): boolean {
57
- return typeof dntShim.dntGlobalThis !== "undefined" && typeof document !== "undefined";
59
+ const load = new Function("return globalThis") as () => NativeGlobalThis;
60
+ const browserGlobal = load();
61
+ return typeof browserGlobal.window !== "undefined" &&
62
+ typeof browserGlobal.document !== "undefined";
58
63
  }
59
64
 
60
65
  function isDenoRuntime(): boolean {
@@ -10,7 +10,7 @@ import {
10
10
  type HealthRpcServer = {
11
11
  name: string;
12
12
  api: TrellisAPI;
13
- natsConnection: { isClosed(): boolean };
13
+ connection?: { status: { phase: string } };
14
14
  mount<M extends keyof TrellisAPI["rpc"] & string>(
15
15
  method: M,
16
16
  handler: (...args: unknown[]) => unknown,
@@ -40,10 +40,15 @@ export async function mountStandardHealthRpc(
40
40
 
41
41
  const method = rpcName as keyof TrellisAPI["rpc"] & string;
42
42
  await server.mount(method, async () => {
43
+ const connection = server.connection;
43
44
  const response = opts?.response
44
45
  ? await opts.response()
45
46
  : await runAllHealthChecks(server.name, {
46
- nats: async () => Result.ok(!server.natsConnection.isClosed()),
47
+ ...(connection
48
+ ? {
49
+ nats: async () => Result.ok(connection.status.phase !== "closed"),
50
+ }
51
+ : {}),
47
52
  ...(opts?.checks ?? {}),
48
53
  });
49
54
  return Result.ok(response);