osra 0.6.2 → 0.6.4

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/build/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { Capable, Remote } from './types.js';
2
2
  import type { DefaultRevivableModules, RevivableContext } from './revivables/index.js';
3
3
  import type { RevivableModule } from './revivables/index.js';
4
- import type { StartConnectionsOptions } from './connections/utils.js';
4
+ import type { Connected, Contextual, Exposed, StartConnectionsOptions } from './connections/utils.js';
5
5
  import type { Transport } from './utils/transport.js';
6
+ import type { IsJsonOnlyTransport } from './utils/type-guards.js';
6
7
  import type { BadFieldValue, BadFieldPath, BadFieldParent, ErrorMessage, BadValue, Path, ParentObject } from './utils/capable-check.js';
7
8
  export * from './types.js';
8
9
  export * from './revivables/index.js';
@@ -10,16 +11,61 @@ export * from './connections/index.js';
10
11
  export * from './utils/index.js';
11
12
  /** Synthetic context so `Capable` can narrow on the inferred transport
12
13
  * without an actual context object at the call site. Only `transport`
13
- * matters; the rest is stubbed with the broadest types. */
14
- type ContextOf<TTransport extends Transport> = RevivableContext & {
14
+ * matters; the rest is stubbed with the broadest types.
15
+ * Named for the revivable context specifically: `ContextOf` is the PUBLIC helper for a connection
16
+ * context builder, re-exported from connections/utils, and two of them in one module is a trap. */
17
+ type RevivableContextOf<TTransport extends Transport> = RevivableContext & {
15
18
  transport: TTransport;
16
19
  };
20
+ /** Error text for a failed check. When the value only fails because the
21
+ * transport is JSON (it would pass under the broad `RevivableContext`,
22
+ * whose transport union resolves to structured-clone semantics), blame
23
+ * the transport instead of the value. */
24
+ type CapableCheckMessage<T, TModules extends readonly RevivableModule[], Ctx extends RevivableContext> = IsJsonOnlyTransport<Ctx['transport']> extends true ? [T] extends [Capable<TModules, RevivableContext>] ? 'Value type is only supported on structured-clone transports, not on JSON transports' : 'Value type must resolve to a Capable' : 'Value type must resolve to a Capable';
17
25
  type CapableCheck<T, TModules extends readonly RevivableModule[] = DefaultRevivableModules, Ctx extends RevivableContext = RevivableContext> = T extends Capable<TModules, Ctx> ? T : T & {
18
- [ErrorMessage]: 'Value type must resolve to a Capable';
26
+ [ErrorMessage]: CapableCheckMessage<T, TModules, Ctx>;
19
27
  [BadValue]: BadFieldValue<T, Capable<TModules, Ctx>>;
20
28
  [Path]: BadFieldPath<T, Capable<TModules, Ctx>>;
21
29
  [ParentObject]: BadFieldParent<T, Capable<TModules, Ctx>>;
22
30
  };
23
- export declare const expose: <T = unknown, const TModules extends readonly RevivableModule[] = DefaultRevivableModules, const TTransport extends Transport = Transport, const TValue = Capable<TModules, ContextOf<TTransport>>>(value: CapableCheck<TValue, TModules, ContextOf<TTransport>>, options: StartConnectionsOptions<TModules> & {
31
+ /**
32
+ * Expose a value to whoever connects, and get back what they exposed.
33
+ *
34
+ * Wrap `value` in `context` to build it once per connection, which is what lets one server answer
35
+ * each realm differently (scoped resolvers per app) instead of sharing one object across all of them.
36
+ * A bare function stays a plain exposed endpoint, so the wrapper is what disambiguates the two.
37
+ *
38
+ * The result is both awaitable and async-iterable: awaiting gives the first peer, iterating gives
39
+ * every peer as it connects. Both hand back the same shape.
40
+ *
41
+ * ```ts
42
+ * const remote = await expose(resolvers, { transport }) // the first peer's value
43
+ * for await (const remote of expose(resolvers, { transport })) { } // every peer's value
44
+ * ```
45
+ *
46
+ * `connection` decides what that shape is. Omit it and it is the peer's value, which is what expose
47
+ * has always resolved to. Return whatever a connection should mean instead:
48
+ *
49
+ * ```ts
50
+ * const { value, context } = await expose(resolvers, {
51
+ * transport,
52
+ * connection: ({ value, context }) => ({ value, context }),
53
+ * })
54
+ *
55
+ * for await (const peer of expose(resolvers, {
56
+ * transport,
57
+ * connection: ({ value, context }) => ({ value, context }),
58
+ * })) {
59
+ * if (!allowed(peer.context.origin)) peer.context.abort?.()
60
+ * }
61
+ * ```
62
+ *
63
+ * A peer's identity is whatever the transport can observe merged over whatever the caller declared
64
+ * in `context`. Only a window message carries a browser-set origin and source; a MessagePort message
65
+ * carries neither, so a port-based server declares what it learned when it received the port.
66
+ * Observed fields win over declared ones, so a declaration can never spoof a real origin.
67
+ */
68
+ export declare const expose: <T = unknown, const TModules extends readonly RevivableModule[] = DefaultRevivableModules, const TTransport extends Transport = Transport, const TValue = Capable<TModules, RevivableContextOf<TTransport>>, TResult = Remote<T>>(value: CapableCheck<TValue, TModules, RevivableContextOf<TTransport>> | Contextual<CapableCheck<TValue, TModules, RevivableContextOf<TTransport>>>, options: Omit<StartConnectionsOptions<TModules>, 'connection'> & {
24
69
  transport: TTransport;
25
- }) => Promise<Remote<T>>;
70
+ connection?: (connected: Connected<Remote<T>>) => TResult;
71
+ }) => Exposed<TResult>;