@astrale-os/adapter-cloudflare 0.2.1 → 0.3.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 (64) hide show
  1. package/dist/build.d.ts +2 -1
  2. package/dist/build.d.ts.map +1 -1
  3. package/dist/build.js +1 -1
  4. package/dist/build.js.map +1 -1
  5. package/dist/client.d.ts +14 -13
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +25 -18
  8. package/dist/client.js.map +1 -1
  9. package/dist/cloudflare.d.ts +4 -1
  10. package/dist/cloudflare.d.ts.map +1 -1
  11. package/dist/cloudflare.js +40 -18
  12. package/dist/cloudflare.js.map +1 -1
  13. package/dist/codegen/worker.d.ts +3 -3
  14. package/dist/codegen/worker.d.ts.map +1 -1
  15. package/dist/codegen/worker.js +19 -8
  16. package/dist/codegen/worker.js.map +1 -1
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.js +2 -2
  19. package/dist/params.d.ts +3 -0
  20. package/dist/params.d.ts.map +1 -1
  21. package/package.json +2 -2
  22. package/src/build.ts +2 -1
  23. package/src/client.ts +43 -18
  24. package/src/cloudflare.ts +41 -14
  25. package/src/codegen/worker.ts +19 -8
  26. package/src/index.ts +2 -2
  27. package/src/params.ts +4 -0
  28. package/template/CLAUDE.md +24 -0
  29. package/template/README.md +24 -15
  30. package/template/astrale.config.ts +4 -4
  31. package/template/client/README.md +9 -9
  32. package/template/client/__tests__/app.test.tsx +58 -19
  33. package/template/client/__tests__/harness.ts +16 -0
  34. package/template/client/__tests__/kernel.test.ts +23 -3
  35. package/template/client/src/shell/use-async.ts +4 -1
  36. package/template/client/src/status/components/StatusCard.tsx +115 -5
  37. package/template/client/src/status/hooks/useCheckable.query.ts +48 -40
  38. package/template/client/src/status/index.ts +2 -2
  39. package/template/client/src/status/status.api.ts +18 -1
  40. package/template/client/src/status/status.mappers.ts +89 -6
  41. package/template/client/src/status/status.types.ts +17 -2
  42. package/template/client/src/styles.css +235 -14
  43. package/template/client/src/views/status.tsx +1 -1
  44. package/template/core/monitor/index.ts +2 -2
  45. package/template/core/monitor/node.ts +12 -6
  46. package/template/domain.ts +6 -4
  47. package/template/functions/index.ts +31 -7
  48. package/template/package.json +2 -2
  49. package/template/pnpm-lock.yaml +2780 -0
  50. package/template/runtime/index.ts +8 -17
  51. package/template/runtime/monitoring/index.ts +8 -0
  52. package/template/runtime/{monitor → monitoring/monitor}/check.ts +3 -3
  53. package/template/runtime/{monitor → monitoring/monitor}/index.ts +3 -2
  54. package/template/runtime/{monitor → monitoring/monitor}/seed.ts +19 -10
  55. package/template/runtime/{monitor → monitoring/monitor}/watch.ts +5 -5
  56. package/template/runtime/{status-page → monitoring/page}/add.ts +2 -2
  57. package/template/runtime/{status-page → monitoring/page}/check.ts +2 -2
  58. package/template/runtime/{status-page → monitoring/page}/create.ts +3 -3
  59. package/template/runtime/monitoring/page/index.ts +9 -0
  60. package/template/schema/monitor.ts +6 -8
  61. package/template/views/index.ts +1 -1
  62. package/template/.agents/skills/astrale-cli/SKILL.md +0 -458
  63. package/template/.agents/skills/astrale-domain/SKILL.md +0 -372
  64. package/template/runtime/status-page/index.ts +0 -8
@@ -5,6 +5,8 @@
5
5
  --border: #e5e5e5;
6
6
  --border-strong: #d4d4d8;
7
7
  --card: #ffffff;
8
+ --surface: #f4f4f5;
9
+ --surface-strong: #eceff3;
8
10
  --accent: #2563eb;
9
11
  --accent-soft: rgba(37, 99, 235, 0.1);
10
12
  --warn-bg: #fffbeb;
@@ -39,7 +41,7 @@ body {
39
41
  }
40
42
 
41
43
  .wrap {
42
- max-width: 42rem;
44
+ max-width: 64rem;
43
45
  margin: 0 auto;
44
46
  padding: 1.5rem;
45
47
  }
@@ -47,8 +49,9 @@ body {
47
49
  .card {
48
50
  background: var(--card);
49
51
  border: 1px solid var(--border);
50
- border-radius: 0.75rem;
52
+ border-radius: 0.5rem;
51
53
  padding: 1.25rem 1.5rem;
54
+ box-shadow: 0 16px 40px rgba(24, 24, 27, 0.06);
52
55
  }
53
56
 
54
57
  .title {
@@ -92,10 +95,10 @@ body {
92
95
  /* ─── Panel ─────────────────────────────────────────────────────────────── */
93
96
 
94
97
  .panel {
95
- background: var(--card);
96
- border: 1px solid var(--border);
97
- border-radius: 0.7rem;
98
- padding: 1.05rem 1.2rem;
98
+ background: transparent;
99
+ border: 0;
100
+ border-radius: 0;
101
+ padding: 0;
99
102
  }
100
103
 
101
104
  .panel-danger {
@@ -107,11 +110,11 @@ body {
107
110
  align-items: center;
108
111
  justify-content: space-between;
109
112
  gap: 0.75rem;
110
- margin-bottom: 0.85rem;
113
+ margin-bottom: 1rem;
111
114
  }
112
115
 
113
116
  .panel-title {
114
- font-size: 1.1rem;
117
+ font-size: 1.35rem;
115
118
  font-weight: 650;
116
119
  margin: 0;
117
120
  }
@@ -175,14 +178,77 @@ body {
175
178
  text-decoration: underline;
176
179
  }
177
180
 
178
- /* ─── Status row + badge ────────────────────────────────────────────────── */
181
+ /* ─── Status dashboard + badge ──────────────────────────────────────────── */
179
182
 
180
- .status-row {
181
- display: flex;
183
+ .status-dashboard {
184
+ display: grid;
185
+ gap: 1rem;
186
+ }
187
+
188
+ .status-overview {
189
+ display: grid;
190
+ grid-template-columns: minmax(0, 1fr) minmax(16rem, 0.65fr);
191
+ gap: 1rem;
192
+ align-items: stretch;
193
+ padding: 1rem;
194
+ background: var(--surface);
195
+ border: 1px solid var(--border);
196
+ border-radius: 0.5rem;
197
+ }
198
+
199
+ .status-label {
200
+ font-family: var(--mono);
201
+ font-size: 0.7rem;
202
+ color: var(--muted);
203
+ margin: 0 0 0.55rem;
204
+ text-transform: uppercase;
205
+ letter-spacing: 0.06em;
206
+ }
207
+
208
+ .summary-grid {
209
+ display: grid;
210
+ grid-template-columns: repeat(3, minmax(0, 1fr));
211
+ border: 1px solid var(--border);
212
+ border-radius: 0.5rem;
213
+ overflow: hidden;
214
+ background: var(--card);
215
+ }
216
+
217
+ .summary-cell {
218
+ min-width: 0;
219
+ padding: 0.7rem 0.8rem;
220
+ border-left: 1px solid var(--border);
221
+ }
222
+
223
+ .summary-cell:first-child {
224
+ border-left: 0;
225
+ }
226
+
227
+ .summary-value {
228
+ display: block;
229
+ font-size: 1.25rem;
230
+ line-height: 1.1;
231
+ font-weight: 750;
232
+ }
233
+
234
+ .summary-label {
235
+ display: block;
236
+ color: var(--muted);
237
+ font-size: 0.72rem;
238
+ margin-top: 0.15rem;
239
+ }
240
+
241
+ .status-meta {
242
+ display: grid;
243
+ grid-template-columns: max-content minmax(0, 1fr) max-content max-content;
244
+ gap: 0.45rem 0.75rem;
182
245
  align-items: center;
183
- justify-content: space-between;
184
- gap: 0.75rem;
185
- margin: 0 0 1rem;
246
+ color: var(--muted);
247
+ font-size: 0.76rem;
248
+ }
249
+
250
+ .status-meta > span:nth-child(odd) {
251
+ font-family: var(--mono);
186
252
  }
187
253
 
188
254
  .status-badge {
@@ -211,6 +277,116 @@ body {
211
277
  background: var(--unknown);
212
278
  }
213
279
 
280
+ .monitor-section {
281
+ border-top: 1px solid var(--border);
282
+ padding-top: 1rem;
283
+ }
284
+
285
+ .monitor-section-head {
286
+ display: flex;
287
+ align-items: center;
288
+ justify-content: space-between;
289
+ gap: 0.75rem;
290
+ margin-bottom: 0.45rem;
291
+ }
292
+
293
+ .monitor-section-head h3 {
294
+ font-size: 0.95rem;
295
+ margin: 0;
296
+ }
297
+
298
+ .refreshing {
299
+ font-family: var(--mono);
300
+ font-size: 0.7rem;
301
+ color: var(--accent);
302
+ background: var(--accent-soft);
303
+ border-radius: 0.35rem;
304
+ padding: 0.15rem 0.4rem;
305
+ }
306
+
307
+ .monitor-list {
308
+ border: 1px solid var(--border);
309
+ border-radius: 0.5rem;
310
+ overflow: hidden;
311
+ }
312
+
313
+ .monitor-row {
314
+ display: grid;
315
+ grid-template-columns: 8.5rem minmax(0, 1fr) minmax(17rem, 0.8fr);
316
+ gap: 1rem;
317
+ align-items: center;
318
+ padding: 0.85rem 0.95rem;
319
+ border-top: 1px solid var(--border);
320
+ background: var(--card);
321
+ }
322
+
323
+ .monitor-row:first-child {
324
+ border-top: 0;
325
+ }
326
+
327
+ .monitor-status {
328
+ display: flex;
329
+ flex-direction: column;
330
+ align-items: flex-start;
331
+ gap: 0.4rem;
332
+ }
333
+
334
+ .monitor-row .status-badge {
335
+ font-size: 0.72rem;
336
+ padding: 0.2rem 0.5rem;
337
+ border-radius: 0.35rem;
338
+ }
339
+
340
+ .weight {
341
+ font-family: var(--mono);
342
+ font-size: 0.68rem;
343
+ color: var(--muted);
344
+ background: var(--surface);
345
+ border-radius: 0.35rem;
346
+ padding: 0.15rem 0.4rem;
347
+ }
348
+
349
+ .weight-critical {
350
+ color: var(--err);
351
+ background: var(--err-soft);
352
+ }
353
+
354
+ .monitor-main {
355
+ min-width: 0;
356
+ }
357
+
358
+ .monitor-main h4 {
359
+ margin: 0 0 0.12rem;
360
+ font-size: 0.95rem;
361
+ }
362
+
363
+ .monitor-metrics {
364
+ display: grid;
365
+ grid-template-columns: repeat(3, minmax(0, 1fr));
366
+ gap: 0.5rem;
367
+ margin: 0;
368
+ }
369
+
370
+ .monitor-metrics div {
371
+ min-width: 0;
372
+ padding: 0.45rem 0.55rem;
373
+ background: var(--surface);
374
+ border-radius: 0.4rem;
375
+ }
376
+
377
+ .monitor-metrics dt {
378
+ color: var(--muted);
379
+ font-size: 0.68rem;
380
+ margin-bottom: 0.1rem;
381
+ }
382
+
383
+ .monitor-metrics dd {
384
+ margin: 0;
385
+ font-family: var(--mono);
386
+ font-size: 0.75rem;
387
+ word-break: break-word;
388
+ }
389
+
214
390
  /* ─── Buttons ───────────────────────────────────────────────────────────── */
215
391
 
216
392
  .check-btn {
@@ -286,3 +462,48 @@ body {
286
462
  transform: rotate(360deg);
287
463
  }
288
464
  }
465
+
466
+ @media (max-width: 760px) {
467
+ .wrap {
468
+ padding: 0.75rem;
469
+ }
470
+
471
+ .card {
472
+ padding: 1rem;
473
+ }
474
+
475
+ .panel-head,
476
+ .status-overview,
477
+ .monitor-row {
478
+ grid-template-columns: 1fr;
479
+ }
480
+
481
+ .panel-head,
482
+ .monitor-section-head {
483
+ align-items: flex-start;
484
+ }
485
+
486
+ .status-meta {
487
+ grid-template-columns: max-content minmax(0, 1fr);
488
+ }
489
+
490
+ .monitor-metrics {
491
+ grid-template-columns: repeat(3, minmax(0, 1fr));
492
+ }
493
+ }
494
+
495
+ @media (max-width: 460px) {
496
+ .summary-grid,
497
+ .monitor-metrics {
498
+ grid-template-columns: 1fr;
499
+ }
500
+
501
+ .summary-cell {
502
+ border-left: 0;
503
+ border-top: 1px solid var(--border);
504
+ }
505
+
506
+ .summary-cell:first-child {
507
+ border-top: 0;
508
+ }
509
+ }
@@ -14,7 +14,7 @@ import { StatusCard } from '@/status'
14
14
 
15
15
  export function StatusView(shell: ShellState) {
16
16
  return (
17
- <ViewFrame shell={shell} title="Status" subline="astrale view">
17
+ <ViewFrame shell={shell} title="Status page" subline="monitoring view">
18
18
  {(session, nodeId) =>
19
19
  nodeId ? (
20
20
  // Keyed by node id so a target hot-swap remounts with fresh state.
@@ -1,8 +1,8 @@
1
1
  /**
2
- * The monitor bounded context's PURE core, in one place: schema accessors
2
+ * The monitoring bounded context's PURE core, in one place: schema accessors
3
3
  * (`keys`), the health status rule (`health`), and node identity/layout/seed
4
4
  * data (`node`). No I/O, no clock/RNG — all deterministic + testable.
5
- * `runtime/monitor/` imports the operations' logic from here.
5
+ * `runtime/monitoring/` imports the operations' logic from here.
6
6
  */
7
7
  export * from './keys'
8
8
  export * from './health'
@@ -5,9 +5,10 @@
5
5
  * node writes) stay in `runtime/`, so this file is deterministic and testable.
6
6
  */
7
7
 
8
- /** Where each kind of node lives in the graph (domain layout; `seed` creates the folders). */
9
- export const MONITORS_PARENT = '/monitors'
10
- export const STATUS_PAGES_PARENT = '/status-pages'
8
+ /** Where monitoring nodes live in the graph (domain layout; `seed` creates the folders). */
9
+ export const MONITORING_PARENT = '/monitoring'
10
+ export const MONITORS_PARENT = `${MONITORING_PARENT}/monitors`
11
+ export const STATUS_PAGES_PARENT = `${MONITORING_PARENT}/pages`
11
12
 
12
13
  /** Deterministic URL-/name-safe stem (lowercased, non-alnum → `-`, clamped). Pure. */
13
14
  export function slugify(text: string): string {
@@ -44,14 +45,19 @@ export interface StarterMonitor {
44
45
  * a real site. Fixed slugs keep `seed` idempotent across reinstalls.
45
46
  */
46
47
  export const STARTERS: readonly StarterMonitor[] = [
47
- { slug: 'astrale', name: 'Astrale', url: 'https://astrale.ai', critical: true },
48
+ {
49
+ slug: 'astrale',
50
+ name: 'Astrale homepage',
51
+ url: 'https://astrale.ai',
52
+ critical: true,
53
+ },
48
54
  {
49
55
  slug: 'httpbin-200',
50
- name: 'httpbin (200)',
56
+ name: 'HTTP 200 smoke check',
51
57
  url: 'https://httpbin.org/status/200',
52
58
  critical: false,
53
59
  },
54
60
  ]
55
61
 
56
62
  /** The status page `seed` creates, watching every starter monitor. */
57
- export const STARTER_PAGE = { slug: 'status', name: 'Status' } as const
63
+ export const STARTER_PAGE = { slug: 'status', name: 'Public status' } as const
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * domain.ts — the WORKER-SAFE domain definition: what the domain IS (its
3
- * `schema`, `methods`, `deps`, `views`, `functions`, `client`) plus its identity
3
+ * `schema`, `methods`, `deps`, `views`, `functions`) plus its identity
4
4
  * (`origin` defaults to `schema.domain`; `postInstall`). Everything is wired
5
5
  * EXPLICITLY here — a renamed or mistyped module is a compile error at this
6
6
  * call, never a silently-missing route. The handlers live in `runtime/` (the
@@ -11,7 +11,7 @@
11
11
  * so your folder layout is invisible to it — reorganize freely; only this wiring
12
12
  * has to stay put. The deploy adapter is attached separately in
13
13
  * `astrale.config.ts` via `deploy(domain, …)`, keeping its node-only code
14
- * (wrangler, filesystem) out of the worker bundle.
14
+ * (wrangler, filesystem, frontend builds) out of the worker bundle.
15
15
  */
16
16
  import { defineDomain } from '@astrale-os/sdk'
17
17
 
@@ -27,7 +27,9 @@ export const domain = defineDomain({
27
27
  deps,
28
28
  views,
29
29
  functions,
30
- client: { dir: 'client' },
31
- postInstall: `/:${schema.domain}:class.Monitor:seed`,
30
+ // Reference the `seed` function directly — the SDK derives its path from the
31
+ // `functions` map, so a rename can't leave a stale string. The kernel calls it
32
+ // once after install, as __SYSTEM__. (A class method would be `'class.X:seed'`.)
33
+ postInstall: functions.seed,
32
34
  requires: [],
33
35
  })
@@ -1,9 +1,33 @@
1
1
  /**
2
- * Function registry — one file per standalone Function under `functions/`,
3
- * listed here. Each becomes a Function node at `/<origin>/core/functions/<key>`
4
- * whose `binding.remoteUrl` the SDK stamps with the worker's public URL at
5
- * install. (Note: the `postInstall` hook must be a CLASS-hosted static method —
6
- * standalone Functions live at tree paths, which the kernel's origin guard
7
- * refuses for postInstall.)
2
+ * Standalone-function registry — one entry per callable that is NOT a method of
3
+ * a class. Each becomes a first-class domain MEMBER: a `Function` node at
4
+ * `/<origin>/functions/<key>` with an `of_domain` edge (slug `function.<key>`),
5
+ * so it is addressable by the semantic domain path `/:<origin>:function.<key>`
6
+ * (e.g. as a `postInstall` target see `domain.ts`) on top of its worker route
7
+ * `/functions/<key>`. The SDK stamps `binding.remoteUrl` with the worker's public
8
+ * URL at install. The map key is the slug (single source of truth).
9
+ *
10
+ * A standalone function's `execute` receives the same request context as a
11
+ * method MINUS `self` (it is not node-bound): `{ params, kernel, deps, auth, … }`.
8
12
  */
9
- export const functions = {}
13
+ import { defineRemoteFunction } from '@astrale-os/sdk'
14
+ import { z } from 'zod'
15
+
16
+ import type { Deps } from '../deps'
17
+
18
+ import { monitor } from '../runtime/monitoring'
19
+
20
+ export const functions = {
21
+ // Post-install bootstrap, wired as `postInstall` in `domain.ts`. The kernel
22
+ // calls it ONCE after install, as __SYSTEM__ (its delegation minted for this
23
+ // function's own identity), so the domain comes up demonstrable. Must stay
24
+ // idempotent — a re-install runs it again. `auth: 'required'` (the default)
25
+ // makes `ctx.kernel` non-null; the body delegates to the per-operation seed
26
+ // logic in `runtime/monitor/seed.ts`.
27
+ seed: defineRemoteFunction<Record<string, never>, { seeded: number }, Deps>({
28
+ inputSchema: z.object({}),
29
+ outputSchema: z.object({ seeded: z.number().int() }),
30
+ authorize: async () => undefined,
31
+ execute: ({ kernel, deps }) => monitor.seed(kernel, deps.prober()),
32
+ }),
33
+ }
@@ -14,10 +14,10 @@
14
14
  "typecheck": "tsgo --noEmit"
15
15
  },
16
16
  "dependencies": {
17
- "@astrale-os/adapter-cloudflare": ">=0.2.1 <1.0.0",
17
+ "@astrale-os/adapter-cloudflare": ">=0.3.0 <1.0.0",
18
18
  "@astrale-os/kernel-core": ">=0.4.3 <1.0.0",
19
19
  "@astrale-os/kernel-dsl": ">=0.1.2 <1.0.0",
20
- "@astrale-os/sdk": ">=0.1.9 <1.0.0",
20
+ "@astrale-os/sdk": ">=0.2.0 <1.0.0",
21
21
  "@hono/node-server": "^1.19.0",
22
22
  "zod": "^4.3.6"
23
23
  },