@codyswann/lisa 2.191.14 → 2.192.1

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 (98) hide show
  1. package/dist/configs/eslint/harper-fabric.d.ts.map +1 -1
  2. package/dist/configs/eslint/harper-fabric.js +5 -0
  3. package/dist/configs/eslint/harper-fabric.js.map +1 -1
  4. package/harper-fabric/copy-contents/.prettierignore +1 -0
  5. package/harper-fabric/copy-contents/gitignore +7 -0
  6. package/harper-fabric/copy-overwrite/.github/dependabot.yml +47 -0
  7. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-early-return-in-search-loop.yml +27 -0
  8. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-empty-conditions-with-sort.yml +45 -0
  9. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-full-table-scan.yml +33 -0
  10. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/require-statuscode-on-thrown-error.yml +41 -0
  11. package/harper-fabric/copy-overwrite/knip.json +1 -0
  12. package/harper-fabric/copy-overwrite/tsconfig.eslint.json +1 -0
  13. package/harper-fabric/merge/.oxlintrc.json +1 -0
  14. package/oxlint/harper-fabric.json +1 -0
  15. package/package.json +1 -1
  16. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa-agy/plugin.json +1 -1
  19. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  22. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo-agy/plugin.json +1 -1
  29. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric/generated-artifact-globs.txt +1 -0
  34. package/plugins/lisa-harper-fabric/hooks/block-generated-artifact-edits.sh +51 -0
  35. package/plugins/lisa-harper-fabric/rules/harper-fabric.md +1 -1
  36. package/plugins/lisa-harper-fabric/skills/harper-auth/SKILL.md +48 -0
  37. package/plugins/lisa-harper-fabric/skills/harper-build-and-deploy/SKILL.md +20 -5
  38. package/plugins/lisa-harper-fabric/skills/harper-resources/SKILL.md +35 -0
  39. package/plugins/lisa-harper-fabric/skills/harper-rest-queries/SKILL.md +40 -3
  40. package/plugins/lisa-harper-fabric-agy/generated-artifact-globs.txt +1 -0
  41. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  42. package/plugins/lisa-harper-fabric-agy/skills/harper-auth/SKILL.md +48 -0
  43. package/plugins/lisa-harper-fabric-agy/skills/harper-build-and-deploy/SKILL.md +20 -5
  44. package/plugins/lisa-harper-fabric-agy/skills/harper-resources/SKILL.md +35 -0
  45. package/plugins/lisa-harper-fabric-agy/skills/harper-rest-queries/SKILL.md +40 -3
  46. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-harper-fabric-copilot/generated-artifact-globs.txt +1 -0
  48. package/plugins/lisa-harper-fabric-copilot/hooks/block-generated-artifact-edits.sh +51 -0
  49. package/plugins/lisa-harper-fabric-copilot/rules/harper-fabric.md +1 -1
  50. package/plugins/lisa-harper-fabric-copilot/skills/harper-auth/SKILL.md +48 -0
  51. package/plugins/lisa-harper-fabric-copilot/skills/harper-build-and-deploy/SKILL.md +20 -5
  52. package/plugins/lisa-harper-fabric-copilot/skills/harper-resources/SKILL.md +35 -0
  53. package/plugins/lisa-harper-fabric-copilot/skills/harper-rest-queries/SKILL.md +40 -3
  54. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-harper-fabric-cursor/generated-artifact-globs.txt +1 -0
  56. package/plugins/lisa-harper-fabric-cursor/hooks/block-generated-artifact-edits.sh +51 -0
  57. package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric.mdc +1 -1
  58. package/plugins/lisa-harper-fabric-cursor/skills/harper-auth/SKILL.md +48 -0
  59. package/plugins/lisa-harper-fabric-cursor/skills/harper-build-and-deploy/SKILL.md +20 -5
  60. package/plugins/lisa-harper-fabric-cursor/skills/harper-resources/SKILL.md +35 -0
  61. package/plugins/lisa-harper-fabric-cursor/skills/harper-rest-queries/SKILL.md +40 -3
  62. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  65. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  69. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  70. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  75. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  79. package/plugins/lisa-rails-agy/plugin.json +1 -1
  80. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  84. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  85. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  89. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  90. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  92. package/plugins/src/harper-fabric/generated-artifact-globs.txt +1 -0
  93. package/plugins/src/harper-fabric/hooks/block-generated-artifact-edits.sh +51 -0
  94. package/plugins/src/harper-fabric/rules/harper-fabric.md +1 -1
  95. package/plugins/src/harper-fabric/skills/harper-auth/SKILL.md +48 -0
  96. package/plugins/src/harper-fabric/skills/harper-build-and-deploy/SKILL.md +20 -5
  97. package/plugins/src/harper-fabric/skills/harper-resources/SKILL.md +35 -0
  98. package/plugins/src/harper-fabric/skills/harper-rest-queries/SKILL.md +40 -3
@@ -260,6 +260,54 @@ Guidance:
260
260
  webhook must bypass Harper auth, verify its signature first and keep its table
261
261
  writes narrowly scoped.
262
262
 
263
+ ## Session cookies are `SameSite=None` — guard state-changing POSTs
264
+
265
+ Harper hardcodes the session cookie's `SameSite=None` attribute on HTTPS. The
266
+ browser therefore attaches the session cookie to **cross-site** requests, so a
267
+ same-origin app cannot rely on `SameSite` to block CSRF on cookie-authenticated,
268
+ state-changing routes (`POST`/`PUT`/`PATCH`/`DELETE`).
269
+
270
+ Add an app-side origin check in the resource before mutating. Reject requests
271
+ whose `Origin` (or `Referer` fallback) is not an allowed origin:
272
+
273
+ ```javascript
274
+ const ALLOWED_ORIGINS = new Set([
275
+ 'https://app.example.com',
276
+ ]);
277
+
278
+ function requireSameOrigin(context) {
279
+ const headers = context.requestContext?.headers ?? context.headers;
280
+ const origin =
281
+ headers?.get?.('origin') ??
282
+ headers?.get?.('referer');
283
+ const ok =
284
+ typeof origin === 'string' &&
285
+ [...ALLOWED_ORIGINS].some((allowed) => origin.startsWith(allowed));
286
+ if (!ok) {
287
+ const error = new Error('Cross-origin request rejected');
288
+ error.statusCode = 403; // Harper reads statusCode, not status
289
+ throw error;
290
+ }
291
+ }
292
+
293
+ export class Watchlists extends tables.Watchlists {
294
+ static async post(target, data, context) {
295
+ requireSameOrigin(context);
296
+ // ...authorization and write
297
+ return super.post(target, await data, context);
298
+ }
299
+ }
300
+ ```
301
+
302
+ Guidance:
303
+
304
+ - Call the check on every cookie-authenticated state-changing route. Read-only
305
+ `GET` handlers and token/`Authorization: Bearer` APIs (not cookie-driven) do
306
+ not need it.
307
+ - Prefer an allowlist of exact origins over substring matching that a lookalike
308
+ host could satisfy.
309
+ - This is defense the app owns; Harper will not add it for you.
310
+
263
311
  ## Verification matrix
264
312
 
265
313
  Run the local app, create the test users, and check unauthenticated, reader, and
@@ -50,15 +50,30 @@ What the build actually does:
50
50
 
51
51
  Generated Harper deploy artifacts usually include:
52
52
 
53
- - `harper-app/resources.js`
54
- - `harper-app/resource-*.js`
53
+ - `harper-app/*.js` — every compiled module the build emits to the harper-app
54
+ root (`resources.js`, `resource-*.js`, and any other output such as a route
55
+ negotiation module). The single-star does **not** cross a directory separator,
56
+ so it does not match hand-written shims one level down.
55
57
  - `harper-app/web/**`
56
58
  - `harper-app/lib/**`
57
59
 
60
+ The guard surfaces (`generated-artifact-globs.txt` for the PreToolUse block hook,
61
+ `.gitignore`, `.prettierignore`, the ESLint/oxlint/knip ignores, and
62
+ `tsconfig.eslint.json`) all key off `harper-app/*.js` so a newly-named compiled
63
+ module is protected automatically. **Name compiled resource modules
64
+ `resource-*.ts`** so their JS output is unambiguously generated.
65
+
66
+ If you keep a *hand-written* `.js` at the harper-app root (e.g. an SEO shell),
67
+ the root-level rule would otherwise treat it as generated: re-include it with a
68
+ `!harper-app/<file>.js` line below the managed gitignore block, and add it to
69
+ `.lisa/harper-generated-artifact-allowlist.txt` so the block hook lets you edit
70
+ it. Hand-written shims nested under `harper-app/<route>/index.js` need no
71
+ exemption — the root-level rule never matches them.
72
+
58
73
  Every lint, format, dead-code, search, or generated-artifact guard must ignore
59
- those generated paths unless it is explicitly validating the build output itself.
60
- When a new generated path appears, add it to every relevant ignore surface in the
61
- same change; partial ignores fail later gates in non-obvious ways.
74
+ generated paths unless it is explicitly validating the build output itself. When
75
+ a new generated *directory* appears, add it to every relevant ignore surface in
76
+ the same change; partial ignores fail later gates in non-obvious ways.
62
77
 
63
78
  - **TypeScript under `src/` is source.** `bun run build` produces the deployable
64
79
  Harper assets from it.
@@ -74,6 +74,41 @@ See [[harper-config-yaml]] for the extension wiring, [[harper-schema-graphql]] f
74
74
  how the schema defines the tables resources extend, and [[harper-realtime]] when
75
75
  `subscribe`, `publish`, or WebSocket behavior is part of the feature.
76
76
 
77
+ ## Throwing HTTP status errors
78
+
79
+ Harper's thrown-error response writer reads **`error.statusCode`** (falling back
80
+ to `500`). A plain `error.status` is **ignored** — throw an error with only
81
+ `status` set and every intended `4xx` is served as a `500`. Verified on
82
+ harperdb 4.7.32.
83
+
84
+ Always set `statusCode` (keep `status` too only if callers or tests read it):
85
+
86
+ ```javascript
87
+ static async post(target, data, context) {
88
+ if (!context.user) {
89
+ const error = new Error('Authentication required');
90
+ error.statusCode = 401; // NOT `error.status` — Harper reads statusCode
91
+ throw error;
92
+ }
93
+ // ...
94
+ }
95
+ ```
96
+
97
+ A shared helper keeps every throw site correct:
98
+
99
+ ```javascript
100
+ function throwStatus(message, status) {
101
+ // Set both: `statusCode` is what Harper serves; `status` is kept for
102
+ // returned-response symmetry and any caller/test that reads it.
103
+ throw Object.assign(new Error(message), { status, statusCode: status });
104
+ }
105
+ ```
106
+
107
+ The `harper-require-statuscode-on-thrown-error` ast-grep rule flags errors that
108
+ carry `status` without `statusCode`. Pass `context` through to `super` and nested
109
+ table calls so authorization and the request transaction stay aligned — see
110
+ [[harper-rest-queries]] for context propagation and iterator draining.
111
+
77
112
  ## Project conventions (TS is source)
78
113
 
79
114
  - **Write resources in TypeScript under `src/`. `harper-app/resources.js` is a
@@ -121,6 +121,38 @@ const products = await tables.Products.search({
121
121
  });
122
122
  ```
123
123
 
124
+ ## Sort with no conditions crashes the planner
125
+
126
+ A `search()` that carries a `sort` but an **empty `conditions: []`** array throws
127
+ at runtime — the planner cannot seed the btree scan from the sort attribute. This
128
+ is a latent `500` the first time an unfiltered, sorted collection page is
129
+ requested (verified on harperdb 4.7.32).
130
+
131
+ ```javascript
132
+ // ✗ crashes: sort with nothing to seed the scan
133
+ tables.Advisor.search({
134
+ conditions: [],
135
+ sort: { attribute: 'lastName' },
136
+ });
137
+ ```
138
+
139
+ Seed a floor/sentinel condition on the sort attribute so the planner has an index
140
+ range to walk, then apply the sort:
141
+
142
+ ```javascript
143
+ // ✓ floor condition on the sort attribute seeds the scan
144
+ tables.Advisor.search({
145
+ conditions: [
146
+ { attribute: 'lastName', comparator: 'greater_than_equal', value: '' },
147
+ ],
148
+ sort: { attribute: 'lastName' },
149
+ });
150
+ ```
151
+
152
+ Centralize this in the page helper (`searchPageAndCount`) rather than duplicating
153
+ a sentinel at each call site. The `harper-no-empty-conditions-with-sort` ast-grep
154
+ rule flags the crashing shape.
155
+
124
156
  ## Relationship queries
125
157
 
126
158
  Relationship attributes can be queried with dot syntax when the relationship is
@@ -200,9 +232,14 @@ Useful query keys:
200
232
  | `select` | Projection list. Keep admin-only fields out of public responses. |
201
233
  | `explain` | Debug execution order and index usage while tuning. |
202
234
 
203
- `search()` can return an `AsyncIterable`. When iterating manually or stopping
204
- early, drain it or call the iterator's `return()` in `finally` so Harper can
205
- release the read transaction:
235
+ `search()` can return an `AsyncIterable`. An early `return`/`break` out of a
236
+ `for await (... of tables.X.search(...))` loop abandons the iterator before the
237
+ scan completes and **leaks the open read transaction** (verified on
238
+ harperdb 4.7.32). When iterating manually or stopping early, drain it or call the
239
+ iterator's `return()` in `finally` so Harper releases the read transaction — or
240
+ bound the query (`search({ ..., limit: 1 })`) when you only need the first row.
241
+ The `harper-no-early-return-in-search-loop` ast-grep rule flags early exits from
242
+ these loops:
206
243
 
207
244
  ```javascript
208
245
  const iterator = tables.Products