@astrale-os/adapter-cloudflare 0.4.2 → 0.4.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/adapter-cloudflare",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "Deploy an Astrale domain as a standalone Cloudflare Worker",
5
5
  "keywords": [
6
6
  "adapter",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "jose": "^6.1.3",
35
- "@astrale-os/sdk": "^0.4.2"
35
+ "@astrale-os/sdk": "^0.4.4"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@astrale-os/ox": ">=0.1.0 <1.0.0",
@@ -21,6 +21,8 @@
21
21
  * the child believes it is framed.
22
22
  */
23
23
 
24
+ import { createKernelClientAdapter } from '@astrale-os/shell'
25
+
24
26
  import type { KernelClient } from '@/shell'
25
27
 
26
28
  const INIT_REQUEST_TYPE = 'astrale-shell/init-request'
@@ -204,37 +206,25 @@ export function ok(result: unknown): { result: unknown } {
204
206
 
205
207
  /**
206
208
  * A `KernelClient` for unit tests that exercise feature hooks WITHOUT a
207
- * handshake. Its `call` POSTs the kernel JSON envelope (`{ method, params, id }`)
208
- * so the `installFakeKernel` fetch stub records it and `body.method`/
209
- * `body.params` assertions hold same wire the real `shell.kernel` speaks to a
210
- * JSON kernel. The credential surface (`mintDelegation`/`authToken`/`url`) is
211
- * stubbed minimally the isolated hooks under test only ever touch `call`.
209
+ * handshake the REAL bound client over the fake `fetch`. `call` (and the graph
210
+ * sugar `get`/`query`/`mutate`/…) POST the kernel JSON envelope
211
+ * (`{ method, params, id }`) that `installFakeKernel` records, so `body.method`/
212
+ * `body.params` assertions hold the same wire `shell.kernel` speaks. Built on
213
+ * `createKernelClientAdapter` so it always satisfies `KernelClient` as that
214
+ * surface grows; the deprecated iframe extras (`mintDelegation`/`authToken`/
215
+ * `url`) are stubbed, exactly as the shell adds them around the same bound view.
212
216
  */
213
217
  export function fakeKernelSession(kernelUrl = 'https://k.example.test/api'): KernelClient {
214
- let idSeq = 0
215
- return {
216
- async call(method: string, params: unknown = {}): Promise<unknown> {
217
- idSeq += 1
218
- const res = await fetch(kernelUrl, {
219
- method: 'POST',
220
- headers: {
221
- 'content-type': 'application/vnd.astrale.kernel+json',
222
- accept: 'application/vnd.astrale.kernel+json',
223
- authorization: 'tok-A',
224
- },
225
- body: JSON.stringify({ method, params, id: `c${idSeq}` }),
226
- })
227
- const obj = (await res.json()) as Record<string, unknown>
228
- if (obj.error && typeof obj.error === 'object') {
229
- const err = obj.error as { code?: unknown; message?: unknown }
230
- const code = typeof err.code === 'number' ? err.code : 5000
231
- const message = typeof err.message === 'string' ? err.message : 'Unknown error'
232
- throw new Error(`${code}: ${message}`)
233
- }
234
- return obj.result
235
- },
218
+ const adapter = createKernelClientAdapter({
219
+ url: kernelUrl,
220
+ // Read `globalThis.fetch` per request so `installFakeKernel` (which swaps it
221
+ // in after this session is built) is the one that answers.
222
+ fetch: (input, init) => globalThis.fetch(input as RequestInfo, init),
223
+ })
224
+ const view = adapter.boundView(() => 'tok-A')
225
+ return Object.assign(view, {
236
226
  mintDelegation: async () => '<fake>',
237
- authToken: () => '<fake>',
227
+ authToken: () => 'tok-A',
238
228
  url: kernelUrl,
239
- }
229
+ })
240
230
  }
@@ -4,10 +4,27 @@ import { useCallback, useEffect, useState } from 'react'
4
4
 
5
5
  import { errorMessage, type KernelNode } from './client'
6
6
 
7
- type KernelReadClient = KernelClient & {
8
- get(
9
- path: string,
10
- ): Promise<{ node: { id: string } | null; wire: { nodes: readonly KernelNode[] } }>
7
+ /**
8
+ * The node shape `shell.kernel.get()` resolves — a graph `Node` ({@link
9
+ * KernelClient.get} returns `Node | null`). Derived from the client's own
10
+ * return type so this file never imports server schema; mapped onto the plain
11
+ * {@link KernelNode} the view helpers consume by `toKernelNode`.
12
+ */
13
+ type GraphNode = NonNullable<Awaited<ReturnType<KernelClient['get']>>>
14
+
15
+ /**
16
+ * Project a graph `Node` onto the plain, schema-free {@link KernelNode}. `path`
17
+ * and `class` arrive as typed `Path` instances over the wire — `String()` yields
18
+ * their raw form (and is the identity on a plain string), so this stays correct
19
+ * whether or not the client hydrates them.
20
+ */
21
+ function toKernelNode(node: GraphNode): KernelNode {
22
+ return {
23
+ id: String(node.id),
24
+ path: String(node.path),
25
+ class: String(node.class),
26
+ props: { ...node.props },
27
+ }
11
28
  }
12
29
 
13
30
  export type NodeState =
@@ -38,21 +55,16 @@ export function useNode(
38
55
  }
39
56
 
40
57
  let cancelled = false
41
- const kernel = session as KernelReadClient
42
58
  setState({ status: 'loading' })
43
- kernel
59
+ session
44
60
  .get(`@${nodeId}`)
45
- .then((result) => {
61
+ .then((node) => {
46
62
  if (cancelled) return
47
- const node =
48
- result.node === null
49
- ? null
50
- : (result.wire.nodes.find((n) => n.id === result.node?.id) ?? null)
51
63
  if (node === null) {
52
64
  setState({ status: 'error', message: 'Node not found or not visible' })
53
65
  return
54
66
  }
55
- setState({ status: 'ok', node })
67
+ setState({ status: 'ok', node: toKernelNode(node) })
56
68
  })
57
69
  .catch((err: unknown) => {
58
70
  if (!cancelled) {
@@ -15,10 +15,13 @@ export default defineConfig({
15
15
  environment: 'happy-dom',
16
16
  globals: true,
17
17
  include: ['__tests__/**/*.test.{ts,tsx}', 'src/**/*.test.{ts,tsx}'],
18
- // `@astrale-os/*` ship bundler-targeted ESM (extensionless relative imports).
19
- // vitest externalizes node_modules and uses Node's stricter ESM resolver,
20
- // which wants explicit `.js`; inlining the scope makes vitest transform them
21
- // through vite the same context the build uses. Standard for these deps.
22
- server: { deps: { inline: [/@astrale-os\//] } },
18
+ // `@astrale-os/*` ship bundler-targeted ESM (extensionless relative imports);
19
+ // Node's stricter ESM resolver, which vitest uses for externalized deps,
20
+ // wants explicit `.js`. Pre-bundle the scope's entrypoint with esbuild (a
21
+ // bundlerit resolves extensionless imports), which pulls the whole
22
+ // transitive `@astrale-os/*` graph (shell → kernel-client kernel-core) into
23
+ // one resolvable module. `web` (not `ssr`) is the optimizer the happy-dom
24
+ // environment runs. Standard workaround for these deps.
25
+ deps: { optimizer: { web: { enabled: true, include: ['@astrale-os/shell'] } } },
23
26
  },
24
27
  })