create-ncblock 0.0.39 → 0.0.41
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 +1 -1
- package/scripts/init.ts +39 -23
- package/scripts/utils/templates.ts +53 -8
- package/sdk-version.json +1 -1
- package/templates/worker/.agents/INSTRUCTIONS.md +593 -0
- package/templates/worker/.agents/skills/auth-guide/SKILL.md +227 -0
- package/templates/worker/.agents/skills/sync/SKILL.md +368 -0
- package/templates/worker/.agents/skills/sync-debug/SKILL.md +101 -0
- package/templates/worker/.agents/skills/sync-guide/SKILL.md +253 -0
- package/templates/worker/.agents/skills/sync-guide/api-pagination-patterns.md +661 -0
- package/templates/worker/.agents/skills/sync-guide/examples/incremental-basic.ts +103 -0
- package/templates/worker/.agents/skills/sync-guide/examples/incremental-bimodal.ts +207 -0
- package/templates/worker/.agents/skills/sync-guide/examples/incremental-events.ts +132 -0
- package/templates/worker/.agents/skills/sync-guide/examples/replace-paginated.ts +79 -0
- package/templates/worker/.agents/skills/sync-guide/examples/replace-simple.ts +57 -0
- package/templates/worker/.agents/skills/sync-validate/SKILL.md +60 -0
- package/templates/worker/.claudeignore +2 -0
- package/templates/worker/.codexignore +2 -0
- package/templates/worker/.examples/automation-example.ts +60 -0
- package/templates/worker/.examples/oauth-example.ts +79 -0
- package/templates/worker/.examples/sync-example.ts +184 -0
- package/templates/worker/.examples/tool-example.ts +37 -0
- package/templates/worker/.examples/webhook-example.ts +66 -0
- package/templates/worker/README.md +765 -0
- package/templates/worker/_gitignore +6 -0
- package/templates/worker/docs/custom-tool.png +0 -0
- package/templates/worker/notionhq-workers-0.4.0.tgz +0 -0
- package/templates/worker/package.json +25 -0
- package/templates/worker/src/index.ts +8 -0
- package/templates/worker/tsconfig.json +16 -0
- package/templates/worker/views/empty/AGENTS.md +71 -0
- package/templates/worker/views/empty/README.md +10 -0
- package/templates/worker/views/empty/_gitignore +2 -0
- package/templates/worker/views/empty/custom_blocks.json +4 -0
- package/templates/worker/views/empty/index.html +15 -0
- package/templates/worker/views/empty/package.json +23 -0
- package/templates/worker/views/empty/src/index.css +33 -0
- package/templates/worker/views/empty/src/index.tsx +20 -0
- package/templates/worker/views/empty/tsconfig.json +17 -0
- package/templates/worker/views/empty/vite.config.ts +7 -0
package/package.json
CHANGED
package/scripts/init.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { resolveInitArgs } from "./utils/resolveInitArgs"
|
|
|
18
18
|
import {
|
|
19
19
|
getTemplateByName,
|
|
20
20
|
getTemplates,
|
|
21
|
+
isWorkerTemplate,
|
|
21
22
|
scaffoldTemplate,
|
|
22
23
|
type TemplateMetadata,
|
|
23
24
|
} from "./utils/templates"
|
|
@@ -542,6 +543,7 @@ async function main() {
|
|
|
542
543
|
)
|
|
543
544
|
const dest = resolve(dir)
|
|
544
545
|
const templateDir = resolve(templateBaseDir, selectedTemplate.name)
|
|
546
|
+
const workerShaped = isWorkerTemplate(templateDir)
|
|
545
547
|
|
|
546
548
|
const destNonEmpty = existsSync(dest) && readdirSync(dest).length > 0
|
|
547
549
|
if (destNonEmpty) {
|
|
@@ -578,7 +580,10 @@ async function main() {
|
|
|
578
580
|
// downstream walks a positional block/view ID up to its parent database.
|
|
579
581
|
const blockIdArg = args.block as string | undefined
|
|
580
582
|
const promptedCollection =
|
|
581
|
-
|
|
583
|
+
!workerShaped &&
|
|
584
|
+
args.collection === undefined &&
|
|
585
|
+
blockIdArg === undefined &&
|
|
586
|
+
installDeps
|
|
582
587
|
? (await ask("Database URL/ID (enter to skip):", "skip")).trim()
|
|
583
588
|
: undefined
|
|
584
589
|
const collectionOverride =
|
|
@@ -640,12 +645,14 @@ async function main() {
|
|
|
640
645
|
step("Initialized git repo")
|
|
641
646
|
}
|
|
642
647
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
648
|
+
if (!workerShaped) {
|
|
649
|
+
writeInitialTarget(dest, { env: resolved.env, blockId })
|
|
650
|
+
step(`Seeded .notion/target.json`)
|
|
651
|
+
if (classified?.kind === "view") {
|
|
652
|
+
console.log(
|
|
653
|
+
` ${c.dim}(view ID resolved — using as block id, database ${databaseId ?? "(none)"})${c.reset}`,
|
|
654
|
+
)
|
|
655
|
+
}
|
|
649
656
|
}
|
|
650
657
|
|
|
651
658
|
let connected = false
|
|
@@ -660,7 +667,7 @@ async function main() {
|
|
|
660
667
|
execSync(`${pm} ${installArgs}`, { cwd: dest, stdio: "inherit" })
|
|
661
668
|
step("Installed dependencies")
|
|
662
669
|
|
|
663
|
-
if (databaseId) {
|
|
670
|
+
if (databaseId && !workerShaped) {
|
|
664
671
|
console.log("")
|
|
665
672
|
try {
|
|
666
673
|
runNcblock(dest, ["connect", databaseId, "--quiet"])
|
|
@@ -676,8 +683,6 @@ async function main() {
|
|
|
676
683
|
}
|
|
677
684
|
}
|
|
678
685
|
|
|
679
|
-
const deployCommand = blockId ? `npx ncblock deploy dist/` : undefined
|
|
680
|
-
|
|
681
686
|
console.log(`\n${c.bold} Ready!${c.reset} Next steps:\n`)
|
|
682
687
|
if (dest !== resolve(".")) {
|
|
683
688
|
console.log(` cd ${formatShellPath(dest)}`)
|
|
@@ -685,22 +690,33 @@ async function main() {
|
|
|
685
690
|
if (!installDeps) {
|
|
686
691
|
console.log(` ${pm} install`)
|
|
687
692
|
}
|
|
688
|
-
|
|
689
|
-
if (
|
|
690
|
-
|
|
693
|
+
|
|
694
|
+
if (workerShaped) {
|
|
695
|
+
// Workers build and bind their views/data sources as part of deploy; data
|
|
696
|
+
// sources are wired in code (see AGENTS.md). Carry a non-prod env through.
|
|
697
|
+
const envFlag =
|
|
698
|
+
resolved.env === "production" ? "" : ` --env=${resolved.env}`
|
|
699
|
+
console.log(` ntn${envFlag} workers deploy`)
|
|
700
|
+
console.log("")
|
|
691
701
|
} else {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
)
|
|
695
|
-
|
|
702
|
+
const deployCommand = blockId ? `npx ncblock deploy dist/` : undefined
|
|
703
|
+
console.log(` ${pm} run build`)
|
|
704
|
+
if (deployCommand) {
|
|
705
|
+
console.log(` ${deployCommand}`)
|
|
706
|
+
} else {
|
|
707
|
+
console.log(
|
|
708
|
+
`\n Then, go back to the instructions in Notion and paste the ${c.bold}ntn deploy${c.reset} command.`,
|
|
709
|
+
)
|
|
710
|
+
}
|
|
696
711
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
712
|
+
if (installDeps && !connected) {
|
|
713
|
+
console.log(
|
|
714
|
+
`\n ${c.yellow}No data source connected yet.${c.reset} To wire one up:`,
|
|
715
|
+
)
|
|
716
|
+
console.log(` npx ncblock connect <database-url-or-id>`)
|
|
717
|
+
}
|
|
718
|
+
console.log("")
|
|
702
719
|
}
|
|
703
|
-
console.log("")
|
|
704
720
|
|
|
705
721
|
closePromptInterface()
|
|
706
722
|
}
|
|
@@ -117,6 +117,17 @@ export function getTemplateByName(
|
|
|
117
117
|
)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
// A template is worker-backed if @notionhq/workers is in its dependencies.
|
|
121
|
+
export function isWorkerTemplate(templateDir: string): boolean {
|
|
122
|
+
const pkgPath = resolve(templateDir, "package.json")
|
|
123
|
+
if (!existsSync(pkgPath)) {
|
|
124
|
+
return false
|
|
125
|
+
}
|
|
126
|
+
return Boolean(
|
|
127
|
+
readTemplatePackageJson(pkgPath).dependencies?.["@notionhq/workers"],
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
120
131
|
type ScaffoldTemplateOptions = {
|
|
121
132
|
root: string
|
|
122
133
|
templateDir: string
|
|
@@ -157,6 +168,12 @@ function copyDirectoryContents(
|
|
|
157
168
|
targetDir: string,
|
|
158
169
|
options: {
|
|
159
170
|
overwrite: boolean
|
|
171
|
+
/**
|
|
172
|
+
* Entry names to skip at the top level only. Root README.md and
|
|
173
|
+
* package.json are rewritten by scaffoldTemplate rather than copied;
|
|
174
|
+
* nested ones (e.g. a view subproject's package.json) must copy
|
|
175
|
+
* through untouched.
|
|
176
|
+
*/
|
|
160
177
|
exclude?: Set<string>
|
|
161
178
|
},
|
|
162
179
|
) {
|
|
@@ -174,7 +191,17 @@ function copyDirectoryContents(
|
|
|
174
191
|
const targetPath = resolve(targetDir, targetName)
|
|
175
192
|
|
|
176
193
|
if (entry.isDirectory()) {
|
|
177
|
-
|
|
194
|
+
// Skip local-only artifacts (node_modules, dist, .notion) at every
|
|
195
|
+
// level, not just the template root. These are gitignored or
|
|
196
|
+
// machine-local — e.g. a view subproject's `.notion/` deploy binding —
|
|
197
|
+
// so they only exist in dirty checkouts and must never leak into a
|
|
198
|
+
// scaffold; the top-level `exclude` set doesn't reach nested dirs.
|
|
199
|
+
if (TEMPLATE_LOCAL_ARTIFACTS.has(entry.name)) {
|
|
200
|
+
continue
|
|
201
|
+
}
|
|
202
|
+
copyDirectoryContents(sourcePath, targetPath, {
|
|
203
|
+
overwrite: options.overwrite,
|
|
204
|
+
})
|
|
178
205
|
continue
|
|
179
206
|
}
|
|
180
207
|
|
|
@@ -229,9 +256,12 @@ export function scaffoldTemplate({
|
|
|
229
256
|
overwrite,
|
|
230
257
|
// README.md and package.json are rendered below with the app name and
|
|
231
258
|
// SDK dependency rewritten for the standalone scaffolded project.
|
|
259
|
+
// workers.json is a developer's local deploy binding (workspace + worker
|
|
260
|
+
// id); copying it would make every scaffold deploy over the same worker.
|
|
232
261
|
exclude: new Set([
|
|
233
262
|
"README.md",
|
|
234
263
|
"package.json",
|
|
264
|
+
"workers.json",
|
|
235
265
|
...TEMPLATE_LOCAL_ARTIFACTS,
|
|
236
266
|
]),
|
|
237
267
|
})
|
|
@@ -244,14 +274,25 @@ export function scaffoldTemplate({
|
|
|
244
274
|
})
|
|
245
275
|
}
|
|
246
276
|
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
277
|
+
// pnpm settings a standalone scaffold needs, with the reason for each inline.
|
|
278
|
+
const npmrcSettings: [key: string, value: string][] = [
|
|
279
|
+
// Treat the project as standalone, not a workspace member. If the user
|
|
280
|
+
// scaffolds inside an existing pnpm workspace (e.g. this repo), pnpm would
|
|
281
|
+
// otherwise walk up, find the workspace root, and do a partial install.
|
|
282
|
+
["ignore-workspace", "true"],
|
|
283
|
+
// Lay node_modules out as a flat tree of real directories instead of
|
|
284
|
+
// symlinks into .pnpm. Worker deploys (`ntn workers deploy --local-build`)
|
|
285
|
+
// ship node_modules verbatim, and the symlink layout leaves transitive
|
|
286
|
+
// deps unresolvable in the deploy sandbox (the SDK's `@notionhq/client`
|
|
287
|
+
// import crashes with ERR_MODULE_NOT_FOUND).
|
|
288
|
+
["node-linker", "hoisted"],
|
|
289
|
+
]
|
|
252
290
|
const npmrcPath = resolve(dest, ".npmrc")
|
|
253
291
|
if (overwrite || !existsSync(npmrcPath)) {
|
|
254
|
-
|
|
292
|
+
const npmrc = npmrcSettings
|
|
293
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
294
|
+
.join("\n")
|
|
295
|
+
writeFileSync(npmrcPath, `${npmrc}\n`)
|
|
255
296
|
}
|
|
256
297
|
|
|
257
298
|
const readmeTarget = resolve(dest, "README.md")
|
|
@@ -263,9 +304,13 @@ export function scaffoldTemplate({
|
|
|
263
304
|
})
|
|
264
305
|
}
|
|
265
306
|
|
|
307
|
+
// Worker templates ship their own AGENTS.md (a symlink copyDirectoryContents
|
|
308
|
+
// skips), so materialize it instead of the generic custom-block guide.
|
|
266
309
|
const agentsTarget = resolve(dest, "AGENTS.md")
|
|
267
310
|
if (overwrite || !existsSync(agentsTarget)) {
|
|
268
|
-
const agentsSource =
|
|
311
|
+
const agentsSource = isWorkerTemplate(templateDir)
|
|
312
|
+
? resolve(templateDir, "AGENTS.md")
|
|
313
|
+
: resolve(root, "scripts/scaffold-assets/AGENTS.md")
|
|
269
314
|
writeRenderedFile({
|
|
270
315
|
sourcePath: agentsSource,
|
|
271
316
|
targetPath: agentsTarget,
|
package/sdk-version.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.0.
|
|
1
|
+
{"version":"0.0.41"}
|