@graview/core 0.1.0 → 0.1.2

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 (292) hide show
  1. package/README.md +7 -0
  2. package/dist/app.d.ts +17 -0
  3. package/dist/app.d.ts.map +1 -1
  4. package/dist/app.js.map +1 -1
  5. package/dist/arrange.d.ts +3 -2
  6. package/dist/arrange.d.ts.map +1 -1
  7. package/dist/arrange.js +19 -2
  8. package/dist/arrange.js.map +1 -1
  9. package/dist/beginning.d.ts +5 -2
  10. package/dist/beginning.d.ts.map +1 -1
  11. package/dist/beginning.js +28 -0
  12. package/dist/beginning.js.map +1 -1
  13. package/dist/capabilities.d.ts +32 -0
  14. package/dist/capabilities.d.ts.map +1 -0
  15. package/dist/capabilities.js +31 -0
  16. package/dist/capabilities.js.map +1 -0
  17. package/dist/cli/check/index.d.ts +1 -0
  18. package/dist/cli/check/index.d.ts.map +1 -1
  19. package/dist/cli/check/index.js +1 -0
  20. package/dist/cli/check/index.js.map +1 -1
  21. package/dist/cli/check/lenses.d.ts.map +1 -1
  22. package/dist/cli/check/lenses.js +25 -0
  23. package/dist/cli/check/lenses.js.map +1 -1
  24. package/dist/cli/check/policy.d.ts.map +1 -1
  25. package/dist/cli/check/policy.js +35 -0
  26. package/dist/cli/check/policy.js.map +1 -1
  27. package/dist/cli/check/relations.d.ts.map +1 -1
  28. package/dist/cli/check/relations.js +31 -0
  29. package/dist/cli/check/relations.js.map +1 -1
  30. package/dist/cli/check/views.d.ts +14 -0
  31. package/dist/cli/check/views.d.ts.map +1 -0
  32. package/dist/cli/check/views.js +27 -0
  33. package/dist/cli/check/views.js.map +1 -0
  34. package/dist/cli/check.d.ts.map +1 -1
  35. package/dist/cli/check.js +2 -1
  36. package/dist/cli/check.js.map +1 -1
  37. package/dist/cli/create.d.ts +1 -1
  38. package/dist/cli/create.d.ts.map +1 -1
  39. package/dist/cli/create.js +63 -1
  40. package/dist/cli/create.js.map +1 -1
  41. package/dist/cli/index.d.ts +18 -1
  42. package/dist/cli/index.d.ts.map +1 -1
  43. package/dist/cli/index.js +66 -1
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/conformance/fixtures.d.ts +41 -0
  46. package/dist/conformance/fixtures.d.ts.map +1 -0
  47. package/dist/conformance/fixtures.js +950 -0
  48. package/dist/conformance/fixtures.js.map +1 -0
  49. package/dist/conformance/index.d.ts +54 -0
  50. package/dist/conformance/index.d.ts.map +1 -0
  51. package/dist/conformance/index.js +81 -0
  52. package/dist/conformance/index.js.map +1 -0
  53. package/dist/document/canonical.d.ts +4 -0
  54. package/dist/document/canonical.d.ts.map +1 -0
  55. package/dist/document/canonical.js +29 -0
  56. package/dist/document/canonical.js.map +1 -0
  57. package/dist/document/compile.d.ts +43 -0
  58. package/dist/document/compile.d.ts.map +1 -0
  59. package/dist/document/compile.js +787 -0
  60. package/dist/document/compile.js.map +1 -0
  61. package/dist/document/diff.d.ts +32 -0
  62. package/dist/document/diff.d.ts.map +1 -0
  63. package/dist/document/diff.js +143 -0
  64. package/dist/document/diff.js.map +1 -0
  65. package/dist/document/edit.d.ts +63 -0
  66. package/dist/document/edit.d.ts.map +1 -0
  67. package/dist/document/edit.js +1420 -0
  68. package/dist/document/edit.js.map +1 -0
  69. package/dist/document/expr/analyze.d.ts +14 -0
  70. package/dist/document/expr/analyze.d.ts.map +1 -0
  71. package/dist/document/expr/analyze.js +52 -0
  72. package/dist/document/expr/analyze.js.map +1 -0
  73. package/dist/document/expr/evaluate.d.ts +36 -0
  74. package/dist/document/expr/evaluate.d.ts.map +1 -0
  75. package/dist/document/expr/evaluate.js +344 -0
  76. package/dist/document/expr/evaluate.js.map +1 -0
  77. package/dist/document/expr/index.d.ts +8 -0
  78. package/dist/document/expr/index.d.ts.map +1 -0
  79. package/dist/document/expr/index.js +5 -0
  80. package/dist/document/expr/index.js.map +1 -0
  81. package/dist/document/expr/parse.d.ts +50 -0
  82. package/dist/document/expr/parse.d.ts.map +1 -0
  83. package/dist/document/expr/parse.js +240 -0
  84. package/dist/document/expr/parse.js.map +1 -0
  85. package/dist/document/expr/print.d.ts +4 -0
  86. package/dist/document/expr/print.d.ts.map +1 -0
  87. package/dist/document/expr/print.js +81 -0
  88. package/dist/document/expr/print.js.map +1 -0
  89. package/dist/document/findings.d.ts +15 -0
  90. package/dist/document/findings.d.ts.map +1 -0
  91. package/dist/document/findings.js +30 -0
  92. package/dist/document/findings.js.map +1 -0
  93. package/dist/document/graview-template.d.ts +148 -0
  94. package/dist/document/graview-template.d.ts.map +1 -0
  95. package/dist/document/graview-template.js +450 -0
  96. package/dist/document/graview-template.js.map +1 -0
  97. package/dist/document/index.d.ts +27 -0
  98. package/dist/document/index.d.ts.map +1 -0
  99. package/dist/document/index.js +16 -0
  100. package/dist/document/index.js.map +1 -0
  101. package/dist/document/migrate.d.ts +41 -0
  102. package/dist/document/migrate.d.ts.map +1 -0
  103. package/dist/document/migrate.js +252 -0
  104. package/dist/document/migrate.js.map +1 -0
  105. package/dist/document/patch.d.ts +16 -0
  106. package/dist/document/patch.d.ts.map +1 -0
  107. package/dist/document/patch.js +79 -0
  108. package/dist/document/patch.js.map +1 -0
  109. package/dist/document/rules.d.ts +40 -0
  110. package/dist/document/rules.d.ts.map +1 -0
  111. package/dist/document/rules.js +88 -0
  112. package/dist/document/rules.js.map +1 -0
  113. package/dist/document/schema.d.ts +459 -0
  114. package/dist/document/schema.d.ts.map +1 -0
  115. package/dist/document/schema.js +197 -0
  116. package/dist/document/schema.js.map +1 -0
  117. package/dist/document/template.d.ts +28 -0
  118. package/dist/document/template.d.ts.map +1 -0
  119. package/dist/document/template.js +117 -0
  120. package/dist/document/template.js.map +1 -0
  121. package/dist/document/to-document.d.ts +34 -0
  122. package/dist/document/to-document.d.ts.map +1 -0
  123. package/dist/document/to-document.js +182 -0
  124. package/dist/document/to-document.js.map +1 -0
  125. package/dist/document/upgrade.d.ts +9 -0
  126. package/dist/document/upgrade.d.ts.map +1 -0
  127. package/dist/document/upgrade.js +19 -0
  128. package/dist/document/upgrade.js.map +1 -0
  129. package/dist/document/views.d.ts +65 -0
  130. package/dist/document/views.d.ts.map +1 -0
  131. package/dist/document/views.js +264 -0
  132. package/dist/document/views.js.map +1 -0
  133. package/dist/formats.d.ts +50 -0
  134. package/dist/formats.d.ts.map +1 -0
  135. package/dist/formats.js +75 -0
  136. package/dist/formats.js.map +1 -0
  137. package/dist/graph/graph.d.ts +52 -3
  138. package/dist/graph/graph.d.ts.map +1 -1
  139. package/dist/graph/graph.js +169 -16
  140. package/dist/graph/graph.js.map +1 -1
  141. package/dist/index.d.ts +40 -17
  142. package/dist/index.d.ts.map +1 -1
  143. package/dist/index.js +29 -10
  144. package/dist/index.js.map +1 -1
  145. package/dist/integrity.d.ts +46 -0
  146. package/dist/integrity.d.ts.map +1 -0
  147. package/dist/integrity.js +179 -0
  148. package/dist/integrity.js.map +1 -0
  149. package/dist/invariants/engine.d.ts +8 -0
  150. package/dist/invariants/engine.d.ts.map +1 -1
  151. package/dist/invariants/engine.js +40 -2
  152. package/dist/invariants/engine.js.map +1 -1
  153. package/dist/invariants/types.d.ts +19 -0
  154. package/dist/invariants/types.d.ts.map +1 -1
  155. package/dist/labels.d.ts +65 -0
  156. package/dist/labels.d.ts.map +1 -0
  157. package/dist/labels.js +123 -0
  158. package/dist/labels.js.map +1 -0
  159. package/dist/mutations/define-mutation.d.ts.map +1 -1
  160. package/dist/mutations/define-mutation.js +2 -3
  161. package/dist/mutations/define-mutation.js.map +1 -1
  162. package/dist/mutations/derive-edits.d.ts.map +1 -1
  163. package/dist/mutations/derive-edits.js +20 -1
  164. package/dist/mutations/derive-edits.js.map +1 -1
  165. package/dist/mutations/form.d.ts +9 -0
  166. package/dist/mutations/form.d.ts.map +1 -1
  167. package/dist/mutations/form.js +20 -0
  168. package/dist/mutations/form.js.map +1 -1
  169. package/dist/mutations/node-ref.d.ts +6 -0
  170. package/dist/mutations/node-ref.d.ts.map +1 -1
  171. package/dist/mutations/node-ref.js +22 -8
  172. package/dist/mutations/node-ref.js.map +1 -1
  173. package/dist/mutations/types.d.ts +8 -0
  174. package/dist/mutations/types.d.ts.map +1 -1
  175. package/dist/mutations/words.d.ts +49 -0
  176. package/dist/mutations/words.d.ts.map +1 -0
  177. package/dist/mutations/words.js +61 -0
  178. package/dist/mutations/words.js.map +1 -0
  179. package/dist/ops/log.d.ts +145 -4
  180. package/dist/ops/log.d.ts.map +1 -1
  181. package/dist/ops/log.js +220 -51
  182. package/dist/ops/log.js.map +1 -1
  183. package/dist/ops/revisions.d.ts +66 -0
  184. package/dist/ops/revisions.d.ts.map +1 -0
  185. package/dist/ops/revisions.js +97 -0
  186. package/dist/ops/revisions.js.map +1 -0
  187. package/dist/ops/types.d.ts +49 -1
  188. package/dist/ops/types.d.ts.map +1 -1
  189. package/dist/ops/undo.d.ts +23 -2
  190. package/dist/ops/undo.d.ts.map +1 -1
  191. package/dist/ops/undo.js +107 -1
  192. package/dist/ops/undo.js.map +1 -1
  193. package/dist/ops/withheld.d.ts +37 -0
  194. package/dist/ops/withheld.d.ts.map +1 -0
  195. package/dist/ops/withheld.js +84 -0
  196. package/dist/ops/withheld.js.map +1 -0
  197. package/dist/permissions/policy.d.ts +15 -0
  198. package/dist/permissions/policy.d.ts.map +1 -1
  199. package/dist/permissions/policy.js +28 -1
  200. package/dist/permissions/policy.js.map +1 -1
  201. package/dist/permissions/sight.d.ts +50 -0
  202. package/dist/permissions/sight.d.ts.map +1 -0
  203. package/dist/permissions/sight.js +76 -0
  204. package/dist/permissions/sight.js.map +1 -0
  205. package/dist/permissions/types.d.ts +26 -0
  206. package/dist/permissions/types.d.ts.map +1 -1
  207. package/dist/permissions/types.js.map +1 -1
  208. package/dist/persistence/memory.d.ts.map +1 -1
  209. package/dist/persistence/memory.js +25 -0
  210. package/dist/persistence/memory.js.map +1 -1
  211. package/dist/persistence/sql.d.ts +43 -0
  212. package/dist/persistence/sql.d.ts.map +1 -0
  213. package/dist/persistence/sql.js +154 -0
  214. package/dist/persistence/sql.js.map +1 -0
  215. package/dist/persistence/sqlite.d.ts +17 -3
  216. package/dist/persistence/sqlite.d.ts.map +1 -1
  217. package/dist/persistence/sqlite.js +32 -96
  218. package/dist/persistence/sqlite.js.map +1 -1
  219. package/dist/persistence/types.d.ts +19 -0
  220. package/dist/persistence/types.d.ts.map +1 -1
  221. package/dist/presence.d.ts +31 -0
  222. package/dist/presence.d.ts.map +1 -1
  223. package/dist/presence.js +36 -0
  224. package/dist/presence.js.map +1 -1
  225. package/dist/scaffold/from-template.d.ts +16 -0
  226. package/dist/scaffold/from-template.d.ts.map +1 -0
  227. package/dist/scaffold/from-template.js +157 -0
  228. package/dist/scaffold/from-template.js.map +1 -0
  229. package/dist/scaffold/index.d.ts +10 -1
  230. package/dist/scaffold/index.d.ts.map +1 -1
  231. package/dist/scaffold/index.js +35 -7
  232. package/dist/scaffold/index.js.map +1 -1
  233. package/dist/scaffold/names.d.ts +4 -0
  234. package/dist/scaffold/names.d.ts.map +1 -1
  235. package/dist/scaffold/names.js.map +1 -1
  236. package/dist/scaffold/project.d.ts +1 -1
  237. package/dist/scaffold/project.d.ts.map +1 -1
  238. package/dist/scaffold/project.js +44 -13
  239. package/dist/scaffold/project.js.map +1 -1
  240. package/dist/scaffold/ui.d.ts.map +1 -1
  241. package/dist/scaffold/ui.js +19 -10
  242. package/dist/scaffold/ui.js.map +1 -1
  243. package/dist/schema/define-node.d.ts +20 -0
  244. package/dist/schema/define-node.d.ts.map +1 -1
  245. package/dist/schema/define-node.js +27 -2
  246. package/dist/schema/define-node.js.map +1 -1
  247. package/dist/schema/path.d.ts +19 -0
  248. package/dist/schema/path.d.ts.map +1 -0
  249. package/dist/schema/path.js +34 -0
  250. package/dist/schema/path.js.map +1 -0
  251. package/dist/schema/types.d.ts +6 -0
  252. package/dist/schema/types.d.ts.map +1 -1
  253. package/dist/seen.d.ts +58 -0
  254. package/dist/seen.d.ts.map +1 -0
  255. package/dist/seen.js +194 -0
  256. package/dist/seen.js.map +1 -0
  257. package/dist/store.d.ts +317 -8
  258. package/dist/store.d.ts.map +1 -1
  259. package/dist/store.js +720 -37
  260. package/dist/store.js.map +1 -1
  261. package/dist/testing.d.ts +6 -0
  262. package/dist/testing.d.ts.map +1 -1
  263. package/dist/testing.js +3 -1
  264. package/dist/testing.js.map +1 -1
  265. package/dist/theme/palettes.d.ts.map +1 -1
  266. package/dist/theme/palettes.js +4 -0
  267. package/dist/theme/palettes.js.map +1 -1
  268. package/dist/theme/types.d.ts +9 -0
  269. package/dist/theme/types.d.ts.map +1 -1
  270. package/dist/theme/types.js +4 -0
  271. package/dist/theme/types.js.map +1 -1
  272. package/dist/validate-graph.d.ts +83 -0
  273. package/dist/validate-graph.d.ts.map +1 -0
  274. package/dist/validate-graph.js +288 -0
  275. package/dist/validate-graph.js.map +1 -0
  276. package/dist/version.d.ts +3 -0
  277. package/dist/version.d.ts.map +1 -0
  278. package/dist/version.js +3 -0
  279. package/dist/version.js.map +1 -0
  280. package/dist/views/types.d.ts +8 -0
  281. package/dist/views/types.d.ts.map +1 -1
  282. package/dist/views/types.js +5 -0
  283. package/dist/views/types.js.map +1 -1
  284. package/dist/watched.d.ts +39 -0
  285. package/dist/watched.d.ts.map +1 -1
  286. package/dist/watched.js +94 -1
  287. package/dist/watched.js.map +1 -1
  288. package/dist/who.d.ts +24 -1
  289. package/dist/who.d.ts.map +1 -1
  290. package/dist/who.js +49 -2
  291. package/dist/who.js.map +1 -1
  292. package/package.json +9 -1
@@ -1,3 +1,5 @@
1
+ import { createSqlAdapter } from "./sql.js";
2
+ export { createSqlAdapter } from "./sql.js";
1
3
  /**
2
4
  * The Drizzle/SQLite table shapes this adapter reads and writes, for an app
3
5
  * that wants to declare them in its own Drizzle schema:
@@ -25,107 +27,41 @@ export const SQLITE_TABLE_SHAPE = {
25
27
  };
26
28
  /**
27
29
  * Reads and writes an app's existing `graph_nodes` / `graph_edges` tables —
28
- * the shape the household example already stores. `data` is schemaless JSON on disk and
29
- * becomes a typed node on the way in, validated by the schema registry when
30
- * the snapshot is loaded into a Graph.
30
+ * the shape the household example already stores — through better-sqlite3.
31
+ * The SQL adapter over `sqlFromDatabase(database)`: one implementation, so
32
+ * what holds here holds over a Durable Object's storage too (FR-09).
31
33
  */
32
34
  export function createSqliteAdapter(options) {
33
- const db = options.database;
34
- const nodeTable = options.nodeTable ?? "graph_nodes";
35
- const edgeTable = options.edgeTable ?? "graph_edges";
36
- const opTable = options.opTable ?? "graview_ops";
37
- const scope = options.scopeColumn ?? "household_id";
38
- if (options.createTables) {
39
- db.exec(`
40
- CREATE TABLE IF NOT EXISTS ${nodeTable} (
41
- ${scope} TEXT NOT NULL, id TEXT NOT NULL,
42
- kind TEXT NOT NULL, data TEXT NOT NULL,
43
- PRIMARY KEY (${scope}, id)
44
- );
45
- CREATE TABLE IF NOT EXISTS ${edgeTable} (
46
- ${scope} TEXT NOT NULL, position INTEGER NOT NULL,
47
- kind TEXT NOT NULL, from_id TEXT NOT NULL, to_id TEXT NOT NULL,
48
- PRIMARY KEY (${scope}, position)
49
- );
50
- CREATE TABLE IF NOT EXISTS ${opTable} (
51
- ${scope} TEXT NOT NULL, seq INTEGER NOT NULL, data TEXT NOT NULL,
52
- PRIMARY KEY (${scope}, seq)
53
- );
54
- `);
55
- }
56
- const selectNodes = db.prepare(`SELECT id, kind, data FROM ${nodeTable} WHERE ${scope} = ?`);
57
- const selectEdges = db.prepare(`SELECT kind, from_id, to_id FROM ${edgeTable} WHERE ${scope} = ? ORDER BY position ASC`);
58
- const deleteNodes = db.prepare(`DELETE FROM ${nodeTable} WHERE ${scope} = ?`);
59
- const deleteEdges = db.prepare(`DELETE FROM ${edgeTable} WHERE ${scope} = ?`);
60
- const insertNode = db.prepare(`INSERT INTO ${nodeTable} (${scope}, id, kind, data) VALUES (?, ?, ?, ?)`);
61
- const insertEdge = db.prepare(`INSERT INTO ${edgeTable} (${scope}, position, kind, from_id, to_id) VALUES (?, ?, ?, ?, ?)`);
62
- /**
63
- * The op table is the framework's own, not the app's, so it is created on
64
- * demand. The node and edge tables are the app's and are never touched
65
- * unless `createTables` explicitly asks for them.
66
- */
67
- let opTableReady = false;
68
- function ensureOpTable() {
69
- if (opTableReady)
70
- return;
71
- db.exec(`CREATE TABLE IF NOT EXISTS ${opTable} (
72
- ${scope} TEXT NOT NULL, seq INTEGER NOT NULL, data TEXT NOT NULL,
73
- PRIMARY KEY (${scope}, seq)
74
- )`);
75
- opTableReady = true;
76
- }
77
- const write = db.transaction(((key, snapshot) => {
78
- deleteEdges.run(key);
79
- deleteNodes.run(key);
80
- for (const node of snapshot.nodes) {
81
- insertNode.run(key, node.id, node.kind, JSON.stringify(node));
35
+ const { database, ...tables } = options;
36
+ return createSqlAdapter({ ...sqlFromDatabase(database), ...tables });
37
+ }
38
+ /**
39
+ * better-sqlite3 as the SQL adapter's `exec`, with its own transaction.
40
+ * Each statement is prepared once and kept, and a statement that reads
41
+ * nothing is `run` rather than asked for rows (better-sqlite3 refuses that).
42
+ */
43
+ export function sqlFromDatabase(database) {
44
+ const prepared = new Map();
45
+ const statement = (sql) => {
46
+ let found = prepared.get(sql);
47
+ if (!found) {
48
+ found = database.prepare(sql);
49
+ prepared.set(sql, found);
82
50
  }
83
- snapshot.edges.forEach((edge, position) => {
84
- insertEdge.run(key, position, edge.kind, edge.from, edge.to);
85
- });
86
- }));
51
+ return found;
52
+ };
87
53
  return {
88
- name: "sqlite",
89
- async load(key) {
90
- const nodeRows = selectNodes.all(key);
91
- if (nodeRows.length === 0)
92
- return null;
93
- const edgeRows = selectEdges.all(key);
94
- const nodes = nodeRows.map((row) => {
95
- const parsed = JSON.parse(row.data);
96
- // `id` and `kind` live in columns as well as the JSON blob; the
97
- // columns win so a row is never internally inconsistent.
98
- return { ...parsed, id: row.id, kind: row.kind };
99
- });
100
- const edges = edgeRows.map((row) => ({
101
- kind: row.kind,
102
- from: row.from_id,
103
- to: row.to_id,
104
- }));
105
- return { nodes, edges };
106
- },
107
- async save(key, snapshot) {
108
- write(key, snapshot);
109
- },
110
- async delete(key) {
111
- deleteEdges.run(key);
112
- deleteNodes.run(key);
113
- },
114
- async loadLog(key) {
115
- ensureOpTable();
116
- const rows = db
117
- .prepare(`SELECT data FROM ${opTable} WHERE ${scope} = ? ORDER BY seq ASC`)
118
- .all(key);
119
- return rows.map((row) => JSON.parse(row.data));
120
- },
121
- async appendOps(key, ops) {
122
- if (ops.length === 0)
123
- return;
124
- ensureOpTable();
125
- const insert = db.prepare(`INSERT OR REPLACE INTO ${opTable} (${scope}, seq, data) VALUES (?, ?, ?)`);
126
- for (const op of ops)
127
- insert.run(key, op.seq, JSON.stringify(op));
54
+ sql: {
55
+ exec(sql, ...params) {
56
+ const prepared = statement(sql);
57
+ const reads = prepared.reader ?? /^\s*(SELECT|WITH|PRAGMA|VALUES)\b/i.test(sql);
58
+ if (reads)
59
+ return prepared.all(...params);
60
+ prepared.run(...params);
61
+ return [];
62
+ },
128
63
  },
64
+ transaction: (fn) => database.transaction(fn)(),
129
65
  };
130
66
  }
131
67
  //# sourceMappingURL=sqlite.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/persistence/sqlite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/persistence/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAgB,MAAM,UAAU,CAAC;AAG1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAgC5C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC;IACtC,KAAK,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC;CAChD,CAAC;AAEX;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA6B;IAC/D,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IACxC,OAAO,gBAAgB,CAAC,EAAE,GAAG,eAAe,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAwB;IACtD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IACpD,MAAM,SAAS,GAAG,CAAC,GAAW,EAAmB,EAAE;QACjD,IAAI,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC9B,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,OAAO;QACL,GAAG,EAAE;YACH,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM;gBACjB,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;gBAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,oCAAoC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAChF,IAAI,KAAK;oBAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;gBAC1C,QAAQ,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;gBACxB,OAAO,EAAE,CAAC;YACZ,CAAC;SACF;QACD,WAAW,EAAE,CAAI,EAAW,EAAK,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAa,CAAC,EAAO;KAC/E,CAAC;AACJ,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import type { GraphSnapshot } from "../graph/types.js";
2
+ import type { Epoch, LogArchive } from "../ops/log.js";
2
3
  import type { Operation } from "../ops/types.js";
3
4
  /**
4
5
  * The framework owns the reactive graph, invariants, diff and undo;
@@ -18,5 +19,23 @@ export interface PersistenceAdapter<Scope = string> {
18
19
  /** Optional: adapters that keep history append the log too. */
19
20
  loadLog?(scope: Scope): Promise<Operation[]>;
20
21
  appendOps?(scope: Scope, ops: readonly Operation[]): Promise<void>;
22
+ /**
23
+ * Optional: the epochs the log folds from (FR-27), kept beside it. An
24
+ * adapter without them reopens a store with none recorded, and ship has
25
+ * it adopt what it holds as its first epoch on each open.
26
+ */
27
+ loadEpochs?(scope: Scope): Promise<Epoch[]>;
28
+ saveEpochs?(scope: Scope, epochs: readonly Epoch[]): Promise<void>;
29
+ /**
30
+ * Optional (FR-23): compaction behind an undo horizon. Moves the ops
31
+ * before `checkpoint.seq`, and the epochs before it, into the archive,
32
+ * and makes `checkpoint` the first epoch. From then on `loadLog` returns
33
+ * the ops from its seq on and `loadEpochs` the checkpoint and what came
34
+ * after it, so a normal open loads nothing older; `loadArchive` returns
35
+ * what was moved, oldest first, for a full export. Nothing is deleted.
36
+ * An adapter that keeps no epochs keeps no checkpoint, and has neither.
37
+ */
38
+ compact?(scope: Scope, checkpoint: Epoch): Promise<void>;
39
+ loadArchive?(scope: Scope): Promise<LogArchive>;
21
40
  }
22
41
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/persistence/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB,CAAC,KAAK,GAAG,MAAM;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,+DAA+D;IAC/D,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAC7C,SAAS,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/persistence/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB,CAAC,KAAK,GAAG,MAAM;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,+DAA+D;IAC/D,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAC7C,SAAS,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE;;;;OAIG;IACH,UAAU,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAC5C,UAAU,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE;;;;;;;;OAQG;IACH,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,WAAW,CAAC,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACjD"}
@@ -28,6 +28,37 @@ export interface PresenceChannel {
28
28
  }
29
29
  /** How long a presence stands after its last word: three missed heartbeats at the poll's own pace. */
30
30
  export declare const PRESENCE_TTL_MS = 2500;
31
+ /**
32
+ * HOW LONG A PRESENCE FROM SOMEWHERE ELSE STANDS (FR-13). A list that came
33
+ * over a wire was stamped by a server's clock and read by a browser's, and
34
+ * it arrives at the poll's pace rather than the heartbeat's, so it is given
35
+ * four times a tab's own grace. Past it a participant is gone whether or
36
+ * not the channel ever said so: a host's channel that forgets to drop
37
+ * somebody does not keep them on the map.
38
+ */
39
+ export declare const REMOTE_PRESENCE_TTL_MS: number;
40
+ /** The parts of a participant key: who, and which tab of theirs. */
41
+ export interface Participant {
42
+ readonly kind: "human" | "agent" | "rule" | "system";
43
+ readonly id?: string;
44
+ readonly session?: string;
45
+ }
46
+ /**
47
+ * THE ONE DIALECT. A participant is `kind:id:session`: the op log's own
48
+ * reading of an author (`Author.kind`, `.id`, `.session`), a figure's key on
49
+ * the map, and what the wire's presence routes carry, so a figure and its
50
+ * edits are the same person by construction. A host that says who is here
51
+ * from its own server writes this, and only this.
52
+ */
53
+ export declare function participantKey(participant: Participant): string;
54
+ /**
55
+ * A participant key read back. The kind is everything before the first
56
+ * colon and the session everything after the last, so an id that holds a
57
+ * colon (`mcp:claude`) survives. Null for anything that is not a key.
58
+ */
59
+ export declare function parseParticipant(key: string): (Participant & {
60
+ readonly session: string;
61
+ }) | null;
31
62
  /**
32
63
  * The others as they are now: what arrived, minus what has gone quiet, minus
33
64
  * yourself. Pure, so a test can ask what a viewer sees without a channel.
@@ -1 +1 @@
1
- {"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,kGAAkG;IAClG,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,mCAAmC;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/B,yFAAyF;IACzF,KAAK,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,QAAQ,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAChE,mCAAmC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,sGAAsG;AACtG,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,EACpC,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,MAAwB,EAC/B,IAAI,CAAC,EAAE,MAAM,GACZ,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAevB;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,SAAS,EAAE,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAWtF"}
1
+ {"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,kGAAkG;IAClG,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,mCAAmC;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/B,yFAAyF;IACzF,KAAK,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,QAAQ,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAChE,mCAAmC;IACnC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,sGAAsG;AACtG,eAAO,MAAM,eAAe,OAAO,CAAC;AAEpC;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAE1D,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,WAAW,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAQjG;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,EACpC,OAAO,EAAE,SAAS,QAAQ,EAAE,EAC5B,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,MAAwB,EAC/B,IAAI,CAAC,EAAE,MAAM,GACZ,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAevB;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,SAAS,EAAE,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAWtF"}
package/dist/presence.js CHANGED
@@ -12,6 +12,42 @@
12
12
  */
13
13
  /** How long a presence stands after its last word: three missed heartbeats at the poll's own pace. */
14
14
  export const PRESENCE_TTL_MS = 2500;
15
+ /**
16
+ * HOW LONG A PRESENCE FROM SOMEWHERE ELSE STANDS (FR-13). A list that came
17
+ * over a wire was stamped by a server's clock and read by a browser's, and
18
+ * it arrives at the poll's pace rather than the heartbeat's, so it is given
19
+ * four times a tab's own grace. Past it a participant is gone whether or
20
+ * not the channel ever said so: a host's channel that forgets to drop
21
+ * somebody does not keep them on the map.
22
+ */
23
+ export const REMOTE_PRESENCE_TTL_MS = PRESENCE_TTL_MS * 4;
24
+ const PARTICIPANT_KINDS = new Set(["human", "agent", "rule", "system"]);
25
+ /**
26
+ * THE ONE DIALECT. A participant is `kind:id:session`: the op log's own
27
+ * reading of an author (`Author.kind`, `.id`, `.session`), a figure's key on
28
+ * the map, and what the wire's presence routes carry, so a figure and its
29
+ * edits are the same person by construction. A host that says who is here
30
+ * from its own server writes this, and only this.
31
+ */
32
+ export function participantKey(participant) {
33
+ return `${participant.kind}:${participant.id ?? ""}:${participant.session ?? ""}`;
34
+ }
35
+ /**
36
+ * A participant key read back. The kind is everything before the first
37
+ * colon and the session everything after the last, so an id that holds a
38
+ * colon (`mcp:claude`) survives. Null for anything that is not a key.
39
+ */
40
+ export function parseParticipant(key) {
41
+ const first = key.indexOf(":");
42
+ const last = key.lastIndexOf(":");
43
+ if (first < 0 || last === first)
44
+ return null;
45
+ const kind = key.slice(0, first);
46
+ if (!PARTICIPANT_KINDS.has(kind))
47
+ return null;
48
+ const id = key.slice(first + 1, last);
49
+ return { kind: kind, ...(id ? { id } : {}), session: key.slice(last + 1) };
50
+ }
15
51
  /**
16
52
  * The others as they are now: what arrived, minus what has gone quiet, minus
17
53
  * yourself. Pure, so a test can ask what a viewer sees without a channel.
@@ -1 +1 @@
1
- {"version":3,"file":"presence.js","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAiCH,sGAAsG;AACtG,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAoC,EACpC,OAA4B,EAC5B,GAAW,EACX,QAAgB,eAAe,EAC/B,IAAa;IAEb,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAC;IACzC,KAAK,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAC;QAC5C,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,KAAK;YAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC7E,CAAC;IACD,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAC/B,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACxG,CAAC;IACD,IAAI,IAAI,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,CAAuB,EAAE,CAAuB;IAC3E,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,CACL,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,WAAW;QAC/B,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;QACjB,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG;QACf,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;QACjB,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC;QACrC,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,IAAI,IAAI,CAAC;QAC/C,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,IAAI,IAAI,CAAC,CACpD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"presence.js","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { GraviewTemplate } from "../document/graview-template.js";
2
+ import { type Ids } from "./names.js";
3
+ /** The kind a project's UI leads with, and the act its seat is gated on: the first kind something creates. */
4
+ export declare function templateKind(template: GraviewTemplate): {
5
+ readonly kind: string;
6
+ readonly plural: string;
7
+ readonly gate: string;
8
+ };
9
+ export declare function documentJson(template: GraviewTemplate): string;
10
+ export declare function templateJson(template: GraviewTemplate): string;
11
+ export declare function documentAppTs(ids: Ids): string;
12
+ export declare function documentSchemaTs(ids: Ids): string;
13
+ export declare function documentBrandTs(ids: Ids): string;
14
+ export declare function documentTest(ids: Ids): string;
15
+ export declare function documentReadmeLayout(ids: Ids, run: string): string;
16
+ //# sourceMappingURL=from-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"from-template.d.ts","sourceRoot":"","sources":["../../src/scaffold/from-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,KAAK,GAAG,EAAyB,MAAM,YAAY,CAAC;AAmB7D,8GAA8G;AAC9G,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAQjI;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAE9D;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAE9D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAkC9C;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAOjD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAiBhD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CA+C7C;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAalE"}
@@ -0,0 +1,157 @@
1
+ import { escapeString, slugify } from "./names.js";
2
+ /*
3
+ * A PROJECT FROM A TEMPLATE (FR-08): the same checkout `graview create`
4
+ * always writes, with the declaration KEPT AS THE DOCUMENT.
5
+ *
6
+ * `src/domain/app.json` is the template's document, and `src/domain/app.ts`
7
+ * compiles it with `compileDocument` when the domain loads. The other choice
8
+ * — writing TypeScript from the document — would need a generator for every
9
+ * construct the document has (expression rules, effects, guards, refusal
10
+ * sentences, view specs) and would then be a second declaration that could
11
+ * drift from the first. Kept as the document, the project IS the template's
12
+ * app: `graview describe` says the same of both by construction, the studio
13
+ * and `editDocument` change it as data, and a template shared back out is the
14
+ * file as it stands. The UI, the tests, the CI and the scripts are the ones
15
+ * every project gets; the template itself sits at the root as
16
+ * `template.json`, for `graview apply --template` to set a store up from.
17
+ */
18
+ /** The kind a project's UI leads with, and the act its seat is gated on: the first kind something creates. */
19
+ export function templateKind(template) {
20
+ const document = template.document;
21
+ const kinds = Object.keys(document.kinds ?? {});
22
+ const acts = Object.entries(document.acts ?? {});
23
+ const creating = kinds.map((kind) => [kind, acts.find(([, act]) => act.creates === kind)?.[0]]).find(([, act]) => act !== undefined);
24
+ const kind = creating?.[0] ?? kinds[0] ?? "item";
25
+ const plural = slugify(document.kinds?.[kind]?.plural ?? `${kind}s`) || `${kind}s`;
26
+ return { kind, plural, gate: creating?.[1] ?? acts[0]?.[0] ?? `add-${kind}` };
27
+ }
28
+ export function documentJson(template) {
29
+ return `${JSON.stringify(template.document, null, 2)}\n`;
30
+ }
31
+ export function templateJson(template) {
32
+ return `${JSON.stringify(template, null, 2)}\n`;
33
+ }
34
+ export function documentAppTs(ids) {
35
+ return `import { Store, type AnySchema, type GraviewApp, type StoreOptions } from "@graview/core";
36
+ import { compileDocument, sayFindings } from "@graview/core/document";
37
+ import document from "./app.json" with { type: "json" };
38
+
39
+ /**
40
+ * THE DECLARATION IS A DOCUMENT: app.json, compiled when this module loads.
41
+ * It runs no code of its own, so it is the same app here, in a host that
42
+ * accepts documents from strangers, and in the template it came from.
43
+ * \`graview check\` and \`graview describe\` read it through this module or
44
+ * straight from the file; edit it, or open it in the studio, and the
45
+ * compiler says what is wrong with the JSON path to fix it at.
46
+ */
47
+ const compiled = compileDocument(document);
48
+ if (!compiled.ok) {
49
+ throw new Error(\`src/domain/app.json does not compile:\\n\${sayFindings(compiled.findings)}\`);
50
+ }
51
+
52
+ export const ${ids.appVar}: GraviewApp = compiled.app;
53
+
54
+ export type ${ids.StoreType} = Store<AnySchema>;
55
+
56
+ export function createStore(options: Partial<StoreOptions<AnySchema>> = {}): ${ids.StoreType} {
57
+ return new Store<AnySchema>({
58
+ schema: ${ids.appVar}.schema,
59
+ mutations: ${ids.appVar}.mutations ?? [],
60
+ invariants: ${ids.appVar}.invariants ?? [],
61
+ ...(${ids.appVar}.policy ? { policy: ${ids.appVar}.policy } : {}),
62
+ ...options,
63
+ });
64
+ }
65
+
66
+ export default ${ids.appVar};
67
+ `;
68
+ }
69
+ export function documentSchemaTs(ids) {
70
+ return `import { ${ids.appVar} } from "./app.js";
71
+
72
+ /** The schema the document compiles to, under the name the UI imports it by. */
73
+ export const ${ids.schemaVar} = ${ids.appVar}.schema;
74
+ export type ${ids.SchemaType} = typeof ${ids.schemaVar};
75
+ `;
76
+ }
77
+ export function documentBrandTs(ids) {
78
+ return `import { brandFromAccent, DARK, LIGHT, type Brand } from "@graview/core";
79
+ import { ${ids.appVar} } from "./app.js";
80
+
81
+ /**
82
+ * The document's brand when it declares one (\`brand.accent\` in app.json);
83
+ * otherwise both schemes derived from one accent, measured against AA.
84
+ */
85
+ function brandOf(): Brand {
86
+ if (${ids.appVar}.brand) return ${ids.appVar}.brand;
87
+ const derived = brandFromAccent({ accent: "${ids.accent}", base: { dark: DARK, light: LIGHT } });
88
+ if (!derived.ok) throw new Error(\`${escapeString(ids.name)} cannot be derived from ${ids.accent}: \${derived.why}\`);
89
+ return { name: ${ids.appVar}.name, schemes: derived.schemes };
90
+ }
91
+
92
+ export const ${ids.brandVar}: Brand = brandOf();
93
+ `;
94
+ }
95
+ export function documentTest(ids) {
96
+ return `import { checkApp, type Principal } from "@graview/core";
97
+ import { instantiateTemplate } from "@graview/core/document";
98
+ import { describe, expect, it } from "vitest";
99
+ import template from "../template.json" with { type: "json" };
100
+ import document from "../src/domain/app.json" with { type: "json" };
101
+ import { ${ids.appVar}, createStore } from "../src/domain/app.js";
102
+
103
+ /**
104
+ * The domain tier has no DOM in it, so these run headless. The declaration
105
+ * is the template's document until you change it; the setup test holds the
106
+ * template's own acts to the document as it stands.
107
+ */
108
+
109
+ describe("the declaration", () => {
110
+ it("passes its own check", () => {
111
+ const result = checkApp(${ids.appVar});
112
+ expect(result.findings.filter((f) => f.severity === "error")).toEqual([]);
113
+ expect(result.ok).toBe(true);
114
+ });
115
+
116
+ it("compiles from the document it keeps", () => {
117
+ expect(${ids.appVar}.name).toBe(document.name);
118
+ });
119
+ });
120
+
121
+ describe("the template's setup", () => {
122
+ const setUp = () => {
123
+ const made = instantiateTemplate({ ...template, document });
124
+ if (!made.ok) throw new Error(made.findings.map((f) => \`\${f.path}: \${f.message}\`).join("\\n"));
125
+ return made;
126
+ };
127
+
128
+ it("runs as one batch, and one undo takes it back", () => {
129
+ const store = createStore();
130
+ const author: Principal = { kind: "system", id: "template:${escapeString(ids.packageName)}" };
131
+ const calls = setUp().setup;
132
+ if (calls.length === 0) return;
133
+ for (const call of calls) {
134
+ store.apply({ name: call.name, args: call.args }, { author, batch: "setup", intent: call.intent });
135
+ }
136
+ expect(new Set(store.log.all().map((op) => op.batch))).toEqual(new Set(["setup"]));
137
+ store.undo("setup", { author });
138
+ expect(store.graph.allNodes()).toEqual([]);
139
+ });
140
+ });
141
+ `;
142
+ }
143
+ export function documentReadmeLayout(ids, run) {
144
+ return `src/domain/ the declaration — no React in here; this is what graview check reads
145
+ app.json the declaration document: kinds, acts, rules, policy, brand, views
146
+ app.ts compiles app.json with compileDocument; createStore
147
+ schema.ts the compiled schema, under the name the UI imports
148
+ brand.ts the document's brand, or one derived from an accent
149
+ src/ui/
150
+ views.tsx registerDefaultViews, then your own where the generic one is wrong
151
+ app.tsx the provider, the Shell primitive, and a seat — under sixty lines
152
+ pages.tsx the ${ids.kind}'s page on the routed face, in your words, over the derived ones
153
+ src/main.tsx the theme, the store that remembers, the two faces
154
+ template.json the template this project was made from: \`${run} apply-template\` sets a store up from it
155
+ tests/ the declaration checks clean, and the template's setup runs as one undoable batch`;
156
+ }
157
+ //# sourceMappingURL=from-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"from-template.js","sourceRoot":"","sources":["../../src/scaffold/from-template.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { GraviewTemplate } from "../document/graview-template.js";
1
2
  export { pascal, slugify, titleCase, validateScaffoldOptions } from "./names.js";
2
3
  export { GRAVIEW_PACKAGES, LINKED_PACKAGES } from "./project.js";
3
4
  export interface ScaffoldOptions {
@@ -47,6 +48,14 @@ export interface ScaffoldOptions {
47
48
  * Two is a gap rather than a taste.
48
49
  */
49
50
  readonly workspace?: boolean;
51
+ /**
52
+ * A template made anywhere — Graview Cloud's shape (FR-08). The project
53
+ * keeps its document as the declaration (`src/domain/app.json`, compiled
54
+ * when the domain loads) and the template beside it as `template.json`,
55
+ * for `graview apply --template` to set a store up from. Read it with
56
+ * `readGraviewTemplate` first; this trusts what it is handed.
57
+ */
58
+ readonly template?: GraviewTemplate;
50
59
  }
51
60
  export interface ScaffoldFile {
52
61
  readonly path: string;
@@ -62,5 +71,5 @@ export interface Scaffold {
62
71
  readonly port: number;
63
72
  readonly linked: boolean;
64
73
  }
65
- export declare function scaffoldProject(options: ScaffoldOptions): Scaffold;
74
+ export declare function scaffoldProject(given: ScaffoldOptions): Scaffold;
66
75
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,iEAAiE;IACjE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzC,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,KAAK,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAID,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ,CA6HlE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEvE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,iEAAiE;IACjE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzC,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,KAAK,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAID,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,QAAQ,CAyJhE"}
@@ -17,15 +17,26 @@ import { slugify, titleCase, camel, pascal, validateScaffoldOptions } from "./na
17
17
  import { SURVEY_SAYS, AUDIT_SAYS, A11Y_SAYS, harness, workspaceRoot, tsconfigBase, rootVitest, packageJson, tsconfig, tsconfigBuild, viteConfig, gitignore, readme, ciYml, } from "./project.js";
18
18
  import { schemaTs, mutationsTs, invariantsTs, brandTs, appTs, domainTest } from "./domain.js";
19
19
  import { indexHtml, embedHtml, embedTsx, viewsTsx, uiAppTsx, pagesTsx, mainTsx } from "./ui.js";
20
+ import { documentAppTs, documentBrandTs, documentJson, documentSchemaTs, documentTest, templateJson, templateKind } from "./from-template.js";
20
21
  export { pascal, slugify, titleCase, validateScaffoldOptions } from "./names.js";
21
22
  export { GRAVIEW_PACKAGES, LINKED_PACKAGES } from "./project.js";
22
- export function scaffoldProject(options) {
23
+ export function scaffoldProject(given) {
24
+ /*
25
+ * FROM A TEMPLATE, the kind the UI leads with is the template's first kind
26
+ * that something creates, and its seat is gated on that act — unless the
27
+ * caller named a kind of the document's itself.
28
+ */
29
+ const led = given.template ? templateKind(given.template) : undefined;
30
+ const options = led
31
+ ? { ...given, kind: given.kind ?? led.kind, plural: given.plural ?? (given.kind === undefined ? led.plural : `${given.kind}s`) }
32
+ : given;
23
33
  const problems = validateScaffoldOptions(options);
24
34
  if (problems.length > 0)
25
35
  throw new Error(problems.join("\n"));
26
36
  const name = options.name.trim();
27
37
  const kind = options.kind ?? "item";
28
38
  const plural = options.plural ?? `${kind}s`;
39
+ const template = options.template;
29
40
  const packageName = options.packageName ?? slugify(name);
30
41
  const packageManager = options.packageManager ?? "pnpm";
31
42
  const port = options.port ?? 5170;
@@ -77,7 +88,27 @@ export function scaffoldProject(options) {
77
88
  range,
78
89
  packageManager,
79
90
  packageName,
91
+ gate: led && given.kind === undefined ? led.gate : `add-${kind}`,
92
+ fromTemplate: template !== undefined,
80
93
  };
94
+ /*
95
+ * THE DECLARATION: TypeScript written for one kind, or — from a template —
96
+ * the template's document kept as the document (see ./from-template.ts).
97
+ */
98
+ const domain = template
99
+ ? [
100
+ { path: "src/domain/app.json", contents: documentJson(template) },
101
+ { path: "src/domain/app.ts", contents: documentAppTs(ids) },
102
+ { path: "src/domain/schema.ts", contents: documentSchemaTs(ids) },
103
+ { path: "src/domain/brand.ts", contents: documentBrandTs(ids) },
104
+ ]
105
+ : [
106
+ { path: "src/domain/schema.ts", contents: schemaTs(ids) },
107
+ { path: "src/domain/mutations.ts", contents: mutationsTs(ids) },
108
+ { path: "src/domain/invariants.ts", contents: invariantsTs(ids) },
109
+ { path: "src/domain/brand.ts", contents: brandTs(ids) },
110
+ { path: "src/domain/app.ts", contents: appTs(ids) },
111
+ ];
81
112
  const files = [
82
113
  { path: "package.json", contents: packageJson(ids, workspace) },
83
114
  { path: "tsconfig.json", contents: tsconfig(workspace) },
@@ -87,18 +118,15 @@ export function scaffoldProject(options) {
87
118
  { path: "embed.html", contents: embedHtml(ids) },
88
119
  { path: ".gitignore", contents: gitignore() },
89
120
  { path: "README.md", contents: readme(ids) },
90
- { path: "src/domain/schema.ts", contents: schemaTs(ids) },
91
- { path: "src/domain/mutations.ts", contents: mutationsTs(ids) },
92
- { path: "src/domain/invariants.ts", contents: invariantsTs(ids) },
93
- { path: "src/domain/brand.ts", contents: brandTs(ids) },
94
- { path: "src/domain/app.ts", contents: appTs(ids) },
121
+ ...domain,
95
122
  { path: "src/ui/views.tsx", contents: viewsTsx(ids) },
96
123
  { path: "src/ui/app.tsx", contents: uiAppTsx(ids) },
97
124
  { path: "src/ui/pages.tsx", contents: pagesTsx(ids) },
98
125
  { path: "src/main.tsx", contents: mainTsx(ids) },
99
126
  { path: "src/embed.tsx", contents: embedTsx(ids) },
100
- { path: "tests/domain.test.ts", contents: domainTest(ids) },
127
+ { path: "tests/domain.test.ts", contents: template ? documentTest(ids) : domainTest(ids) },
101
128
  { path: ".github/workflows/ci.yml", contents: ciYml(ids) },
129
+ ...(template ? [{ path: "template.json", contents: templateJson(template) }] : []),
102
130
  ];
103
131
  if (!workspace) {
104
132
  return { files, name, packageName, kind, plural, packageManager, port, linked: link !== undefined };