@owlmeans/create-app 0.1.18-rc.5 → 0.1.18-rc.7

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": "@owlmeans/create-app",
3
- "version": "0.1.18-rc.5",
3
+ "version": "0.1.18-rc.7",
4
4
  "license": "MIT",
5
5
  "description": "Scaffold a minimal fullstack OwlMeans Common app — common + api + web workspaces, shadcn UI navigation/layout, no auth, and a session-scoped in-memory resource. Deploys agent skills via @owlmeans/agent-skills by default.",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  "template"
30
30
  ],
31
31
  "dependencies": {
32
- "@owlmeans/agent-skills": "^0.1.18-rc.5"
32
+ "@owlmeans/agent-skills": "^0.1.18-rc.6"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@owlmeans/dep-config": "workspace:*",
@@ -11,12 +11,12 @@
11
11
  "typecheck": "tsc -b"
12
12
  },
13
13
  "dependencies": {
14
- "@owlmeans/server-app": "^0.1.16",
15
- "@owlmeans/static-resource": "^0.1.16",
14
+ "@owlmeans/server-app": "^0.1.18-rc.0",
15
+ "@owlmeans/static-resource": "^0.1.18-rc.0",
16
16
  "__APP_SLUG__-common": "workspace:^"
17
17
  },
18
18
  "devDependencies": {
19
- "@owlmeans/dep-config": "^0.1.16",
19
+ "@owlmeans/dep-config": "^0.1.18-rc.0",
20
20
  "@types/node": "^24.10.1",
21
21
  "typescript": "^7.0.2"
22
22
  }
@@ -10,5 +10,9 @@ export const makeContext = <C extends Config, T extends Context<C>>(cfg: C): T =
10
10
  // data lives in process memory and is cleared when the api restarts.
11
11
  appendStaticResource<C, T>(context, SESSION_ITEMS)
12
12
 
13
+ // A child context has to inherit THIS factory, not the layer's — otherwise a derived context
14
+ // is built without the resource registered above and every lookup on it throws.
15
+ context.makeContext = makeContext as typeof context.makeContext
16
+
13
17
  return context
14
18
  }
@@ -19,15 +19,15 @@
19
19
  "typecheck": "tsc -b"
20
20
  },
21
21
  "dependencies": {
22
- "@owlmeans/config": "^0.1.16",
23
- "@owlmeans/entrypoint": "^0.1.16",
24
- "@owlmeans/error": "^0.1.16",
25
- "@owlmeans/resource": "^0.1.16",
26
- "@owlmeans/route": "^0.1.16",
22
+ "@owlmeans/config": "^0.1.18-rc.0",
23
+ "@owlmeans/entrypoint": "^0.1.18-rc.0",
24
+ "@owlmeans/error": "^0.1.18-rc.0",
25
+ "@owlmeans/resource": "^0.1.18-rc.0",
26
+ "@owlmeans/route": "^0.1.18-rc.0",
27
27
  "ajv": "^8.17.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@owlmeans/dep-config": "^0.1.16",
30
+ "@owlmeans/dep-config": "^0.1.18-rc.0",
31
31
  "@types/node": "^24.10.1",
32
32
  "typescript": "^7.0.2"
33
33
  }
@@ -11,19 +11,20 @@
11
11
  "preview": "vite preview"
12
12
  },
13
13
  "dependencies": {
14
- "@owlmeans/client": "^0.1.16",
15
- "@owlmeans/client-config": "^0.1.16",
16
- "@owlmeans/client-context": "^0.1.16",
17
- "@owlmeans/client-entrypoint": "^0.1.16",
18
- "@owlmeans/client-i18n": "^0.1.16",
19
- "@owlmeans/entrypoint": "^0.1.16",
20
- "@owlmeans/route": "^0.1.16",
21
- "@owlmeans/web-client": "^0.1.16",
22
- "@owlmeans/web-panel": "^0.1.16",
23
- "__APP_SLUG__-common": "workspace:^",
14
+ "@owlmeans/client": "^0.1.18-rc.0",
15
+ "@owlmeans/client-config": "^0.1.18-rc.0",
16
+ "@owlmeans/client-context": "^0.1.18-rc.0",
17
+ "@owlmeans/client-entrypoint": "^0.1.18-rc.0",
18
+ "@owlmeans/client-i18n": "^0.1.18-rc.0",
19
+ "@owlmeans/entrypoint": "^0.1.18-rc.0",
20
+ "@owlmeans/route": "^0.1.18-rc.0",
21
+ "@owlmeans/state": "^0.1.18-rc.0",
22
+ "@owlmeans/web-client": "^0.1.18-rc.0",
23
+ "@owlmeans/web-panel": "^0.1.18-rc.0",
24
24
  "@radix-ui/react-label": "^2.1.0",
25
25
  "@radix-ui/react-progress": "^1.1.0",
26
26
  "@radix-ui/react-slot": "^1.1.0",
27
+ "__APP_SLUG__-common": "workspace:^",
27
28
  "ajv": "^8.17.1",
28
29
  "class-variance-authority": "^0.7.0",
29
30
  "clsx": "^2.1.0",
@@ -37,7 +38,7 @@
37
38
  "tailwindcss": "^4.1.13"
38
39
  },
39
40
  "devDependencies": {
40
- "@owlmeans/dep-config": "^0.1.16",
41
+ "@owlmeans/dep-config": "^0.1.18-rc.0",
41
42
  "@tailwindcss/vite": "^4.1.13",
42
43
  "@types/react": "^19.2.17",
43
44
  "@types/react-dom": "^19.2.3",
@@ -1,7 +1,23 @@
1
1
  import { makeContext as makeBasicContext, useContext as useBasicContext } from '@owlmeans/web-panel'
2
+ import { appendStateResource } from '@owlmeans/state'
2
3
  import type { Config, Context } from './types.js'
3
4
 
5
+ /** The alias the session items are stored under. Screens address the store by it, never by path. */
6
+ export const SESSION_STATE = 'session-items'
7
+
4
8
  export const useContext = (): Context => useBasicContext<Config, Context>()
5
9
 
6
- export const makeContext = <C extends Config, T extends Context<C>>(cfg: C): T =>
7
- makeBasicContext<C, T>(cfg)
10
+ export const makeContext = <C extends Config, T extends Context<C>>(cfg: C): T => {
11
+ const context = makeBasicContext<C, T>(cfg)
12
+
13
+ // The framework's client store. A state resource lives ON the context, so a screen, a guard and
14
+ // a service all reach the same records — which is what separates it from a store held beside
15
+ // the app in a module of its own.
16
+ appendStateResource<C, T>(context, SESSION_STATE)
17
+
18
+ // A child context has to inherit THIS factory, not the layer's. Without the line, a derived
19
+ // context is built without the resource registered above and every lookup on it throws.
20
+ context.makeContext = makeContext as typeof context.makeContext
21
+
22
+ return context
23
+ }
@@ -1,7 +1,8 @@
1
1
  import { useEffect, useState, type FC } from 'react'
2
2
  import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
3
+ import { useStoreList } from '@owlmeans/client'
3
4
  import { session, type SessionItem } from '__APP_SLUG__-common'
4
- import { useContext } from '../context.js'
5
+ import { SESSION_STATE, useContext } from '../context.js'
5
6
  import { Button } from '@/components/ui/button'
6
7
  import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
7
8
  import { Input } from '@/components/ui/input'
@@ -20,15 +21,27 @@ const sessionId = (): string => {
20
21
  export const SessionScreen: FC = () => {
21
22
  const ctx = useContext()
22
23
  const sid = sessionId()
23
- const [items, setItems] = useState<SessionItem[]>([])
24
24
  const [text, setText] = useState('')
25
25
  const [busy, setBusy] = useState(false)
26
26
 
27
+ const store = ctx.getStateResource<SessionItem>(SESSION_STATE)
28
+
29
+ /**
30
+ * The list is a live subscription to the state resource, not a piece of component state.
31
+ * Anything that writes a record — this screen or another one — re-renders it, so adding and
32
+ * removing never re-fetch to stay in step. `{}` matches every record; a real filter goes here.
33
+ */
34
+ const items = useStoreList<SessionItem>({ query: {}, resource: SESSION_STATE })
35
+
36
+ // The server is the source of truth; the store is what the screen reads. Fetch once, write
37
+ // what came back into the store, and let the subscription render it.
27
38
  const load = async () => {
28
39
  const [data] = await ctx
29
40
  .entrypoint<ClientEntrypoint<SessionItem[]>>(session.list)
30
41
  .call({ params: { sid } })
31
- setItems(data ?? [])
42
+ for (const item of data ?? []) {
43
+ await store.save(item)
44
+ }
32
45
  }
33
46
 
34
47
  useEffect(() => { void load() }, [])
@@ -37,11 +50,13 @@ export const SessionScreen: FC = () => {
37
50
  if (text.trim() === '') return
38
51
  setBusy(true)
39
52
  try {
40
- await ctx
53
+ const [item] = await ctx
41
54
  .entrypoint<ClientEntrypoint<SessionItem>>(session.add)
42
55
  .call({ params: { sid }, body: { text } })
43
56
  setText('')
44
- await load()
57
+ if (item != null) {
58
+ await store.save(item)
59
+ }
45
60
  } finally {
46
61
  setBusy(false)
47
62
  }
@@ -51,7 +66,7 @@ export const SessionScreen: FC = () => {
51
66
  await ctx
52
67
  .entrypoint<ClientEntrypoint<{ removed: boolean }>>(session.remove)
53
68
  .call({ params: { sid, id } })
54
- await load()
69
+ await store.delete(id)
55
70
  }
56
71
 
57
72
  return (
@@ -75,11 +90,11 @@ export const SessionScreen: FC = () => {
75
90
  <ul className="flex flex-col gap-2">
76
91
  {items.map(item => (
77
92
  <li
78
- key={item.id}
93
+ key={item.record.id}
79
94
  className="flex items-center justify-between rounded-md border px-3 py-2"
80
95
  >
81
- <span>{item.text}</span>
82
- <Button variant="ghost" size="sm" onClick={() => void remove(item.id)}>
96
+ <span>{item.record.text}</span>
97
+ <Button variant="ghost" size="sm" onClick={() => void remove(item.record.id)}>
83
98
  Remove
84
99
  </Button>
85
100
  </li>