@hozu/cli 0.22.0 → 0.24.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 (45) hide show
  1. package/dist/commands/browse-page.d.ts.map +1 -1
  2. package/dist/commands/browse-page.js +6 -1
  3. package/dist/commands/browse-page.js.map +1 -1
  4. package/dist/commands/browse.d.ts +9 -1
  5. package/dist/commands/browse.d.ts.map +1 -1
  6. package/dist/commands/browse.js +73 -8
  7. package/dist/commands/browse.js.map +1 -1
  8. package/dist/commands/call.d.ts.map +1 -1
  9. package/dist/commands/call.js +26 -4
  10. package/dist/commands/call.js.map +1 -1
  11. package/dist/commands/gen.d.ts.map +1 -1
  12. package/dist/commands/gen.js +8 -5
  13. package/dist/commands/gen.js.map +1 -1
  14. package/dist/commands/migrate.d.ts.map +1 -1
  15. package/dist/commands/migrate.js +12 -4
  16. package/dist/commands/migrate.js.map +1 -1
  17. package/dist/commands/request.d.ts +1 -0
  18. package/dist/commands/request.d.ts.map +1 -1
  19. package/dist/commands/request.js +126 -33
  20. package/dist/commands/request.js.map +1 -1
  21. package/dist/contract.d.ts +19 -4
  22. package/dist/contract.d.ts.map +1 -1
  23. package/dist/gen/go.d.ts +9 -2
  24. package/dist/gen/go.d.ts.map +1 -1
  25. package/dist/gen/go.js +127 -23
  26. package/dist/gen/go.js.map +1 -1
  27. package/dist/main.js +1 -1
  28. package/dist/migrate/steps.d.ts +2 -2
  29. package/dist/migrate/steps.d.ts.map +1 -1
  30. package/dist/migrate/steps.js +98 -12
  31. package/dist/migrate/steps.js.map +1 -1
  32. package/dist/remote.d.ts.map +1 -1
  33. package/dist/remote.js +17 -4
  34. package/dist/remote.js.map +1 -1
  35. package/package.json +8 -8
  36. package/schema/browse.schema.json +22 -1
  37. package/schema/call.schema.json +1 -1
  38. package/schema/gen.schema.json +24 -7
  39. package/schema/inspect.schema.json +2 -1
  40. package/schema/migrate.schema.json +10 -2
  41. package/skill/SKILL.md +2 -2
  42. package/skill/topics/data.md +38 -6
  43. package/skill/topics/recipes.md +6 -4
  44. package/skill/topics/testing.md +2 -0
  45. package/skill/topics/views.md +6 -2
@@ -1 +1 @@
1
- {"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hozu/cli",
3
- "version": "0.22.0",
3
+ "version": "0.24.0",
4
4
  "description": "The hozu command: check, map, why, show, get, browse, call, plan, add, build, dev, serve, docs, migrate and skill (all with --json)",
5
5
  "keywords": [
6
6
  "hozu",
@@ -48,14 +48,14 @@
48
48
  "access": "public"
49
49
  },
50
50
  "dependencies": {
51
- "@hozu/core": "0.22.0",
52
- "@hozu/devtools": "0.22.0",
53
- "@hozu/validator": "0.22.0",
54
- "@hozu/machine": "0.22.0",
55
- "@hozu/compiler": "0.22.0",
56
- "@hozu/transform": "0.22.0"
51
+ "@hozu/core": "0.24.0",
52
+ "@hozu/validator": "0.24.0",
53
+ "@hozu/machine": "0.24.0",
54
+ "@hozu/compiler": "0.24.0",
55
+ "@hozu/devtools": "0.24.0",
56
+ "@hozu/transform": "0.24.0"
57
57
  },
58
58
  "devDependencies": {
59
- "create-hozu": "0.22.0"
59
+ "create-hozu": "0.24.0"
60
60
  }
61
61
  }
@@ -110,7 +110,28 @@
110
110
  }
111
111
  },
112
112
  "differs": {
113
- "type": "boolean"
113
+ "type": "boolean",
114
+ "description": "Both modes made a request and the resulting text differs."
115
+ },
116
+ "differences": {
117
+ "type": "array",
118
+ "items": {
119
+ "type": "object",
120
+ "properties": {
121
+ "on": {
122
+ "type": "string"
123
+ },
124
+ "off": {
125
+ "type": "string"
126
+ }
127
+ },
128
+ "required": [
129
+ "on",
130
+ "off"
131
+ ],
132
+ "additionalProperties": false
133
+ },
134
+ "description": "The words that differ, at most three lines (ADR 0070 B6); a URL pair first when the pages differ."
114
135
  },
115
136
  "elsewhere": {
116
137
  "type": "array",
@@ -77,7 +77,7 @@
77
77
  "items": {
78
78
  "type": "string"
79
79
  },
80
- "description": "Tags a mutation invalidated."
80
+ "description": "Tags a mutation or a writing endpoint invalidated."
81
81
  },
82
82
  "refreshes": {
83
83
  "type": "array",
@@ -17,15 +17,25 @@
17
17
  "package": {
18
18
  "type": "string"
19
19
  },
20
- "fingerprint": {
21
- "type": "string"
22
- },
23
20
  "effects": {
24
21
  "type": "array",
25
22
  "items": {
26
- "type": "string"
23
+ "type": "object",
24
+ "properties": {
25
+ "ref": {
26
+ "type": "string"
27
+ },
28
+ "fingerprint": {
29
+ "type": "string"
30
+ }
31
+ },
32
+ "required": [
33
+ "ref",
34
+ "fingerprint"
35
+ ],
36
+ "additionalProperties": false
27
37
  },
28
- "description": "The effects it implements: feature.symbol."
38
+ "description": "The effects it implements (feature.symbol), each with the fingerprint its calls carry (ADR 0070 C3)."
29
39
  },
30
40
  "written": {
31
41
  "type": "boolean",
@@ -37,15 +47,22 @@
37
47
  "type": "string"
38
48
  },
39
49
  "description": "Effects that cannot be remote (the server refuses to start with them, HZ093)."
50
+ },
51
+ "notes": {
52
+ "type": "array",
53
+ "items": {
54
+ "type": "string"
55
+ },
56
+ "description": "Number fields named like an id or a count, which may want z.int() (ADR 0070 C4), and enums without a title that became several Go types, which a title makes one; not diagnostics."
40
57
  }
41
58
  },
42
59
  "required": [
43
60
  "file",
44
61
  "package",
45
- "fingerprint",
46
62
  "effects",
47
63
  "written",
48
- "problems"
64
+ "problems",
65
+ "notes"
49
66
  ],
50
67
  "additionalProperties": false
51
68
  }
@@ -747,7 +747,8 @@
747
747
  "alternate",
748
748
  "env",
749
749
  "session",
750
- "state"
750
+ "state",
751
+ "route"
751
752
  ]
752
753
  },
753
754
  "GuardExpr": {
@@ -41,15 +41,23 @@
41
41
  },
42
42
  "summary": {
43
43
  "type": "string"
44
+ },
45
+ "changes": {
46
+ "type": "array",
47
+ "items": {
48
+ "type": "string"
49
+ }
44
50
  }
45
51
  },
46
52
  "required": [
47
53
  "from",
48
54
  "to",
49
- "summary"
55
+ "summary",
56
+ "changes"
50
57
  ],
51
58
  "additionalProperties": false
52
- }
59
+ },
60
+ "description": "Each step's changes: `summary` joins `changes` with \"; \"."
53
61
  },
54
62
  "changed": {
55
63
  "type": "array",
package/skill/SKILL.md CHANGED
@@ -46,10 +46,10 @@ Hozu is not in your training data: this file and `npx hozu docs <topic>` are the
46
46
  ## Topics (`npx hozu docs <topic>`; `--more`: options, edge cases)
47
47
  | Task | Topic |
48
48
  |---|---|
49
- | a new feature, the files, a complete example | `feature` |
49
+ | a new feature, its files, an example | `feature` |
50
50
  | elements, attributes, events, lists, links, reuse | `views` |
51
51
  | states, events, invoke, timers, guards | `machine` |
52
- | queries, mutations, tags, `fn()`, resolvers | `data` |
52
+ | queries, mutations, tags, `fn()`, resolvers, a database | `data` |
53
53
  | where effects run, `fetch.ts`, browser storage, static hosts | `fetch` |
54
54
  | contracts and the lock | `contracts` |
55
55
  | routes, search, pages, `head`, 403 / 404 | `pages` |
@@ -97,16 +97,44 @@ export default app({
97
97
  ```
98
98
  - The loop: change the declaration in TypeScript → `npx hozu gen` (writes the contract: types, the `Resolvers`
99
99
  interface, `Handler`) → implement the interface until `go test ./...` passes → restart the service → `hozu check`.
100
- A contract older than the declarations is HZ093; the service answers 409 to calls from other declarations.
100
+ A contract older than the declarations is HZ093 naming the changed effects; each effect has its own fingerprint, so
101
+ the service answers 409 only to calls of an effect that changed.
101
102
  - In Go: return a declared error as the error value (`hozu.NotesAddNoteDuplicate{Text: t}`), `hozu.Invalid{…}` for
102
103
  input problems; `ctx.Session` is nil when signed out; `ctx.SetSession(…)` / `ctx.SignOut()` in mutations. Public
103
104
  queries never receive the session. `ctx.File(token)` reads an upload, `ctx.Header` an endpoint's request headers
104
105
  (no cookie), `ctx.Preview` preview mode. The secret is required (16+ characters, the same value on both sides,
105
106
  HZ093): the service trusts the session it is sent, so serve `hozu.Handler(r, hozu.Options{Secret: …})` on a private
106
107
  address (it refuses to start without one).
108
+ - Any other Go error answers 500 with its first line, which reaches `onError` and `Unexpected` as a thrown TypeScript
109
+ error does, with the call's id (`x-hozu-call`) that the service's log line names
110
+ (`hozu: notes.listNotes (call 3fa2c1d0): …`). A service that is not running is `no service answers at <url>`.
107
111
  - `.meta({ title: 'Note' })` on a schema makes it one Go type wherever it appears; `z.int()` is `int64`, a plain
108
- number `float64`. Only `runs: 'server'` effects and JSON endpoints can be remote (HZ093).
109
- - `examples/notes-go` is the reference: the notes app with every resolver in Go.
112
+ number `float64` (`hozu gen` notes number fields named like ids or counts); a string `z.enum` is a named type with
113
+ one constant per member (`hozu.OrderStatusPending`, named by its title or its field). Only `runs: 'server'` effects
114
+ and JSON endpoints can be remote (HZ093).
115
+ - [`examples/notes-go`](https://github.com/olevatorr/Hozu/tree/main/examples/notes-go) is the reference: the notes
116
+ app with every resolver in Go. Its `service/main.go` is all a service needs besides the resolvers (`go.mod` is
117
+ yours; the contract's folder is the `hozu` package):
118
+ ```go
119
+ func main() {
120
+ secret := os.Getenv("NOTES_SERVICE_SECRET") // the app's remote() secret, 16+ characters
121
+ addr := os.Getenv("NOTES_SERVICE_ADDR") // the app's NOTES_SERVICE_URL is http://<addr>/effect
122
+ mux := http.NewServeMux()
123
+ mux.Handle("/effect", hozu.Handler(newResolvers(), hozu.Options{Secret: secret}))
124
+ server := &http.Server{Addr: addr, Handler: mux}
125
+ go func() {
126
+ if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
127
+ log.Fatal(err)
128
+ }
129
+ }()
130
+ stop, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
131
+ defer cancel()
132
+ <-stop.Done() // finish the calls in flight, then exit
133
+ ctx, done := context.WithTimeout(context.Background(), 5*time.Second)
134
+ defer done()
135
+ server.Shutdown(ctx)
136
+ }
137
+ ```
110
138
 
111
139
  ## A database
112
140
  - One pool per process, made in `app.ts`; close it in `app({ dispose: () => pool.end() })` so `hozu get`, `call` and
@@ -118,7 +146,11 @@ export default app({
118
146
  - Data the whole staff shares but only staff may read is `scope: 'user'` with `access` (it is never cached across
119
147
  requests). Share one rule: `const staffOnly = part(({ session }) => session.role !== 'editor')`, then
120
148
  `access: { allow: staffOnly }` on each effect.
121
- - A resolver may answer `fail('Forbidden', { message })` (a row deleted meanwhile, a check `access` cannot make);
122
- with `access: 'signedIn'` its `session` is never null.
149
+ - A resolver may answer `fail('Forbidden', { message })` (a check `access` cannot make); with any access but
150
+ `'anyone'` its `session` is never null.
151
+ - A failure you can expect (a row gone, a state that forbids the change) is a declared error of the effect
152
+ (`errors: { NotFound }`, `fail('NotFound', …)`), handled in `failed` with and without JavaScript. A thrown error is
153
+ `Unexpected`: a server fault (500 on a native post, `Internal error` in production).
123
154
  - Another app writing the same database: give the reading app a signed `endpoint` that `invalidates` the tags, and
124
- call it after a write (`hozu docs endpoints`).
155
+ call it after a write (`hozu docs endpoints`). Every query that app's writes change needs a tag, or only its
156
+ freshness time refreshes it.
@@ -89,16 +89,18 @@ const staffHead = { query: me, render: (m) => ({ title: `${m.name} · Admin` }),
89
89
  const staff = (route, View) => ui.page(route, { views: [Sidebar, View], head: staffHead })
90
90
  export default project({ /* … */ pages: [staff(orders, OrderList), staff(orderDetail, OrderPage), …] })
91
91
  ```
92
- The sidebar's links mark the page shown with `aria-current` by themselves (`aria-[current]:font-bold`).
92
+ The sidebar marks its sections with `current(route)` from its render:
93
+ `'aria-current': current(orders) || current(orderDetail)`, styled `aria-[current]:font-bold`.
93
94
 
94
95
  ## Screens with different state
95
96
  One machine per feature: an order list (filters, selection) and an order page (shipping, refund) are two features,
96
97
  `orders` and `order`, sharing declarations through `exports`. Each machine stays small and its contracts few.
97
98
 
98
99
  ## A multi-step checkout that also works without JavaScript
99
- Each step is a state; the server runs the machine per request, so without JS a step's form posts every earlier field
100
- again as hidden inputs (`ui.input({ type: 'hidden', name: 'line1', value: ctx.line1 })`), and the last step's
101
- mutation receives them all. Prefill from the member with `seed: ({ query }) => ({ email: query(me, {}).email })`.
100
+ Each step is a state and each step's form posts only its own fields: after a native post the server renders the next
101
+ step, and every form on that page carries the machine's state in a signed hidden field, so the next post continues
102
+ from it (going back to edit a step too). Prefill from the member with
103
+ `seed: ({ query }) => ({ email: query(me, {}).email })`.
102
104
 
103
105
  ## A notice after saving
104
106
  A `notice` context field set in `done` and cleared by `after: [{ ms: 4000, target: 'idle' }]` on a `saved` state;
@@ -69,6 +69,8 @@
69
69
  navigation prints `→ <path>` and the new page's lines; a live update on another actor's page prints under the step
70
70
  (`bob: + Milk`).
71
71
  - `≠ DIFFERS` marks a step where both modes made a request and the resulting text differs: a no-JS/JS parity bug.
72
+ It names the differing words (`≠ DIFFERS (on vs off): "#1307" vs "#1306"`): the two modes write twice to the same
73
+ data, so a new row per mode (an order number, a count) differs without a bug.
72
74
  - Errors: uncaught exceptions, `console.error`s, CSP violations and failed requests, each with the page, the
73
75
  resource type and the mode. A 400 re-render of an invalid native post is not an error, and a page answering
74
76
  401, 403, 404 or 410 is the step's status (`→ /notes/n1 (403)`), so an access check exits 0.
@@ -67,9 +67,13 @@ export const Board = ui.view({
67
67
  ## Menus, dialogs, counting
68
68
  - When a query's input changes, the rows stay (`aria-busy` on the parent) and update by key; `pending` shows only
69
69
  before the first answer.
70
- - A link to the page shown gets `aria-current="page"` (`"true"` for its section): `aria-[current]:font-bold`.
70
+ - A link to the address shown gets `aria-current="page"`. Which links mark a section is yours to say: the render's
71
+ `current(route)` is true on that route's pages, so a menu writes
72
+ `ui.a({ href: ui.link(orders, null), 'aria-current': current(orders) || current(orderDetail) }, ['Orders'])` and
73
+ styles `aria-[current]:font-bold`: `true` is written `"page"` on the address itself, `false` writes nothing.
71
74
  - `ui.dialog({ open: is(['editing']), on: { close: ui.send(Cancel, {}) } }, [...])` opens as a modal and closes with
72
- the machine; Escape sends `close`.
75
+ the machine; Escape sends `close`. It needs JavaScript: a dialog that must open without it uses the native
76
+ `commandfor` button (the short form) and closes when the data that shows it changes.
73
77
  - `ui.format.plural(n, { one: '# item', other: '# items' })` picks the case for the page's language (`=0` works).
74
78
  - `null` and `false` render nothing, also inside a constant list:
75
79
  `ui.ul({}, [...kinds.map((k) => (k === 'draft' ? null : ui.li({}, [k])))])`.