create-nextly-app 0.0.2-alpha.64 → 0.0.2-alpha.66
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/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/cli.mjs.map +1 -1
- package/package.json +5 -5
- package/templates/base/AGENTS.md.template +52 -15
- package/templates/plugin/AGENTS.md.template +27 -0
- package/templates/plugin/vitest.config.ts +19 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nextly-app",
|
|
3
|
-
"version": "0.0.2-alpha.
|
|
3
|
+
"version": "0.0.2-alpha.66",
|
|
4
4
|
"description": "CLI to scaffold Nextly in your Next.js project",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"typescript": "^5.9.3",
|
|
43
43
|
"vite-tsconfig-paths": "^5.1.4",
|
|
44
44
|
"vitest": "^4.1.0",
|
|
45
|
-
"@nextlyhq/eslint-config": "0.0.2-alpha.
|
|
46
|
-
"@nextlyhq/eslint-plugin": "0.0.2-alpha.
|
|
47
|
-
"@nextlyhq/telemetry": "0.0.2-alpha.
|
|
48
|
-
"@nextlyhq/tsconfig": "0.0.2-alpha.
|
|
45
|
+
"@nextlyhq/eslint-config": "0.0.2-alpha.66",
|
|
46
|
+
"@nextlyhq/eslint-plugin": "0.0.2-alpha.66",
|
|
47
|
+
"@nextlyhq/telemetry": "0.0.2-alpha.66",
|
|
48
|
+
"@nextlyhq/tsconfig": "0.0.2-alpha.66"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
|
@@ -84,9 +84,9 @@ const slug = typeof doc.slug === "string" ? doc.slug : undefined;
|
|
|
84
84
|
|
|
85
85
|
**`keyParts` is a security boundary, not a performance detail.** Two callers
|
|
86
86
|
whose `keyParts` match share one cache entry. So if the read applies any
|
|
87
|
-
per-caller rule —
|
|
88
|
-
|
|
89
|
-
rows get served to another:
|
|
87
|
+
per-caller rule — a code-defined `access.read` that reads the caller's
|
|
88
|
+
roles or permissions, an API key's narrowed scope — the caller's identity
|
|
89
|
+
has to be IN the key, or one user's rows get served to another:
|
|
90
90
|
|
|
91
91
|
**A shared cache entry is only safe if the read is public for EVERY reader.**
|
|
92
92
|
Two independent things can make it not so, and each needs its own answer:
|
|
@@ -94,16 +94,26 @@ const slug = typeof doc.slug === "string" ? doc.slug : undefined;
|
|
|
94
94
|
- **drafts** — `find()` defaults to `overrideAccess: true`, a trusted server
|
|
95
95
|
read, so a slug filter alone can return an unpublished row. `status:
|
|
96
96
|
"published"` is enforced even on a trusted read and fixes this one.
|
|
97
|
-
- **
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
- **access rules** — a code-defined `access.read` on the collection that
|
|
98
|
+
decides on the caller (their roles, their permissions, whether they are
|
|
99
|
+
signed in at all), or an API key's narrowed scope. `status` does NOT
|
|
100
|
+
evaluate these; it is a draft/published lifecycle filter and nothing more.
|
|
101
|
+
A published row that only some readers may see is still returned by the
|
|
102
|
+
query above.
|
|
103
|
+
|
|
104
|
+
- **field-level read rules** — a field can carry its own `access.read` even
|
|
105
|
+
when the collection declares none. The shared branch below reads with the
|
|
106
|
+
Direct API's default `overrideAccess: true`, which bypasses field rules
|
|
107
|
+
too, so the cached row holds every field and the entry serves fields the
|
|
108
|
+
schema meant to redact. A collection with ANY field-level read rule takes
|
|
109
|
+
the per-caller branch — or selects only fields known to be public.
|
|
110
|
+
|
|
111
|
+
So the decision is: **does this collection declare a read rule, on the
|
|
112
|
+
collection or on any of its fields?**
|
|
103
113
|
|
|
104
114
|
```ts
|
|
105
|
-
// NO
|
|
106
|
-
// entry is correct and gets the full ISR benefit.
|
|
115
|
+
// NO read rule, on the collection OR its fields — the result is identical for
|
|
116
|
+
// every reader, so one shared entry is correct and gets the full ISR benefit.
|
|
107
117
|
// `find()` always returns the list envelope `{ items, meta }`, so a detail route takes the
|
|
108
118
|
// first item — and caches THAT, not the envelope around it.
|
|
109
119
|
cachedFind(
|
|
@@ -119,8 +129,8 @@ const slug = typeof doc.slug === "string" ? doc.slug : undefined;
|
|
|
119
129
|
{ tags: nextlyTags("posts"), keyParts: ["posts", slug] }
|
|
120
130
|
);
|
|
121
131
|
|
|
122
|
-
//
|
|
123
|
-
//
|
|
132
|
+
// A READ RULE — evaluate it as the caller, and key by EVERY dimension the
|
|
133
|
+
// rule reads, not just who the caller is.
|
|
124
134
|
//
|
|
125
135
|
// Both role fields are optional and Nextly reads BOTH: the many-to-many
|
|
126
136
|
// `roles` unioned with the singular `role`. Deduped and sorted, so one role
|
|
@@ -144,8 +154,35 @@ const slug = typeof doc.slug === "string" ? doc.slug : undefined;
|
|
|
144
154
|
on CONTENT changes, and a permission change is not one. Include whatever the
|
|
145
155
|
rules actually read: the role set, the claim, the key's scope.
|
|
146
156
|
|
|
147
|
-
If you are unsure whether a collection
|
|
148
|
-
missing cache is slow; a shared one leaks.
|
|
157
|
+
If you are unsure whether a collection or any of its fields declares a read
|
|
158
|
+
rule, do not cache it. A missing cache is slow; a shared one leaks.
|
|
159
|
+
|
|
160
|
+
## Which Nextly this is, and where its docs are
|
|
161
|
+
|
|
162
|
+
An agent working here will otherwise answer from whatever it remembers of some
|
|
163
|
+
other version. Ask the project instead:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
{{execCommand}} nextly --version # the running core version
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
That is the same version the plugin resolver validates a plugin's `nextly`
|
|
170
|
+
range against, so a compatibility answer and a reported version cannot
|
|
171
|
+
disagree. The dependency range this project pins is in `package.json` under
|
|
172
|
+
`nextly`; the resolved version is what the command above prints.
|
|
173
|
+
|
|
174
|
+
**The authoritative documentation is <https://nextlyhq.com/docs>.** Two files
|
|
175
|
+
are published for machine readers and are the ones to fetch:
|
|
176
|
+
|
|
177
|
+
| file | what it is |
|
|
178
|
+
| ---- | ---------- |
|
|
179
|
+
| <https://nextlyhq.com/llms.txt> | the index — every documentation page, with a one-line summary |
|
|
180
|
+
| <https://nextlyhq.com/llms-full.txt> | the same documentation as one file |
|
|
181
|
+
|
|
182
|
+
Both are generated from the pages the site publishes, so they cannot describe a
|
|
183
|
+
page that does not exist. Neither is version-stamped: they describe the CURRENT
|
|
184
|
+
release, so check the version above before trusting a detail against an older
|
|
185
|
+
pin.
|
|
149
186
|
|
|
150
187
|
## Conventions worth keeping
|
|
151
188
|
|
|
@@ -84,6 +84,33 @@ those slugs a second time as code-owned entities and boot fails with
|
|
|
84
84
|
Assert on behaviour through `t.nextly` rather than on the plugin object: what a
|
|
85
85
|
host observes is the contract, and the object shape is not.
|
|
86
86
|
|
|
87
|
+
## Which Nextly this is, and where its docs are
|
|
88
|
+
|
|
89
|
+
An agent working here will otherwise answer from whatever it remembers of some
|
|
90
|
+
other version. Ask the project instead:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
{{execCommand}} nextly --version # the running core version
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
That is the same version the plugin resolver validates a plugin's `nextly`
|
|
97
|
+
range against, so a compatibility answer and a reported version cannot
|
|
98
|
+
disagree. The dependency range this project pins is in `package.json` under
|
|
99
|
+
`nextly`; the resolved version is what the command above prints.
|
|
100
|
+
|
|
101
|
+
**The authoritative documentation is <https://nextlyhq.com/docs>.** Two files
|
|
102
|
+
are published for machine readers and are the ones to fetch:
|
|
103
|
+
|
|
104
|
+
| file | what it is |
|
|
105
|
+
| ---- | ---------- |
|
|
106
|
+
| <https://nextlyhq.com/llms.txt> | the index — every documentation page, with a one-line summary |
|
|
107
|
+
| <https://nextlyhq.com/llms-full.txt> | the same documentation as one file |
|
|
108
|
+
|
|
109
|
+
Both are generated from the pages the site publishes, so they cannot describe a
|
|
110
|
+
page that does not exist. Neither is version-stamped: they describe the CURRENT
|
|
111
|
+
release, so check the version above before trusting a detail against an older
|
|
112
|
+
pin.
|
|
113
|
+
|
|
87
114
|
## Conventions worth keeping
|
|
88
115
|
|
|
89
116
|
- Version `nextly` compatibility in the factory's `nextly` range, and widen it
|
|
@@ -4,5 +4,24 @@ export default defineConfig({
|
|
|
4
4
|
test: {
|
|
5
5
|
environment: "node",
|
|
6
6
|
include: ["src/**/*.test.ts"],
|
|
7
|
+
/*
|
|
8
|
+
* Sized for an instance boot, because that is what this suite does.
|
|
9
|
+
*
|
|
10
|
+
* `plugin.test.ts` calls `createTestNextly` in `beforeEach`, which builds a
|
|
11
|
+
* DI container, registers the plugin's schema and runs auto-sync against a
|
|
12
|
+
* real SQLite database. Vitest's defaults are sized for a unit test that
|
|
13
|
+
* touches none of that: 5s for a case and 10s for a hook. A boot is about a
|
|
14
|
+
* second and a half on a warm machine, and the first run of a freshly
|
|
15
|
+
* scaffolded project is the least warm moment there is - a cold install, no
|
|
16
|
+
* build cache, whatever the laptop or CI container is doing.
|
|
17
|
+
*
|
|
18
|
+
* This is the first command a new plugin author runs, so a timeout here
|
|
19
|
+
* reads as "the scaffold ships a broken test" rather than "the budget was
|
|
20
|
+
* tight". The monorepo solves the same problem by routing boots to a lane
|
|
21
|
+
* with a 30s budget; a single-package project has one lane and nothing to
|
|
22
|
+
* contend with, so it states the budget instead.
|
|
23
|
+
*/
|
|
24
|
+
testTimeout: 30_000,
|
|
25
|
+
hookTimeout: 30_000,
|
|
7
26
|
},
|
|
8
27
|
});
|