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.
Files changed (40) hide show
  1. package/package.json +1 -1
  2. package/scripts/init.ts +39 -23
  3. package/scripts/utils/templates.ts +53 -8
  4. package/sdk-version.json +1 -1
  5. package/templates/worker/.agents/INSTRUCTIONS.md +593 -0
  6. package/templates/worker/.agents/skills/auth-guide/SKILL.md +227 -0
  7. package/templates/worker/.agents/skills/sync/SKILL.md +368 -0
  8. package/templates/worker/.agents/skills/sync-debug/SKILL.md +101 -0
  9. package/templates/worker/.agents/skills/sync-guide/SKILL.md +253 -0
  10. package/templates/worker/.agents/skills/sync-guide/api-pagination-patterns.md +661 -0
  11. package/templates/worker/.agents/skills/sync-guide/examples/incremental-basic.ts +103 -0
  12. package/templates/worker/.agents/skills/sync-guide/examples/incremental-bimodal.ts +207 -0
  13. package/templates/worker/.agents/skills/sync-guide/examples/incremental-events.ts +132 -0
  14. package/templates/worker/.agents/skills/sync-guide/examples/replace-paginated.ts +79 -0
  15. package/templates/worker/.agents/skills/sync-guide/examples/replace-simple.ts +57 -0
  16. package/templates/worker/.agents/skills/sync-validate/SKILL.md +60 -0
  17. package/templates/worker/.claudeignore +2 -0
  18. package/templates/worker/.codexignore +2 -0
  19. package/templates/worker/.examples/automation-example.ts +60 -0
  20. package/templates/worker/.examples/oauth-example.ts +79 -0
  21. package/templates/worker/.examples/sync-example.ts +184 -0
  22. package/templates/worker/.examples/tool-example.ts +37 -0
  23. package/templates/worker/.examples/webhook-example.ts +66 -0
  24. package/templates/worker/README.md +765 -0
  25. package/templates/worker/_gitignore +6 -0
  26. package/templates/worker/docs/custom-tool.png +0 -0
  27. package/templates/worker/notionhq-workers-0.4.0.tgz +0 -0
  28. package/templates/worker/package.json +25 -0
  29. package/templates/worker/src/index.ts +8 -0
  30. package/templates/worker/tsconfig.json +16 -0
  31. package/templates/worker/views/empty/AGENTS.md +71 -0
  32. package/templates/worker/views/empty/README.md +10 -0
  33. package/templates/worker/views/empty/_gitignore +2 -0
  34. package/templates/worker/views/empty/custom_blocks.json +4 -0
  35. package/templates/worker/views/empty/index.html +15 -0
  36. package/templates/worker/views/empty/package.json +23 -0
  37. package/templates/worker/views/empty/src/index.css +33 -0
  38. package/templates/worker/views/empty/src/index.tsx +20 -0
  39. package/templates/worker/views/empty/tsconfig.json +17 -0
  40. package/templates/worker/views/empty/vite.config.ts +7 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ncblock",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "Create a Notion custom view block project.",
5
5
  "type": "module",
6
6
  "bin": {
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
- args.collection === undefined && blockIdArg === undefined && installDeps
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
- writeInitialTarget(dest, { env: resolved.env, blockId })
644
- step(`Seeded .notion/target.json`)
645
- if (classified?.kind === "view") {
646
- console.log(
647
- ` ${c.dim}(view ID resolved — using as block id, database ${databaseId ?? "(none)"})${c.reset}`,
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
- console.log(` ${pm} run build`)
689
- if (deployCommand) {
690
- console.log(` ${deployCommand}`)
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
- console.log(
693
- `\n Then, go back to the instructions in Notion and paste the ${c.bold}ntn deploy${c.reset} command.`,
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
- if (installDeps && !connected) {
698
- console.log(
699
- `\n ${c.yellow}No data source connected yet.${c.reset} To wire one up:`,
700
- )
701
- console.log(` npx ncblock connect <database-url-or-id>`)
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
- copyDirectoryContents(sourcePath, targetPath, options)
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
- // Scaffolded projects are standalone, not workspace members. If the user
248
- // scaffolds inside an existing pnpm workspace (e.g. this repo), pnpm walks
249
- // up, finds the workspace root, and the install ends up partial. A local
250
- // .npmrc with `ignore-workspace=true` makes pnpm treat the project as
251
- // standalone regardless of where it lives.
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
- writeFileSync(npmrcPath, "ignore-workspace=true\n")
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 = resolve(root, "scripts/scaffold-assets/AGENTS.md")
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.39"}
1
+ {"version":"0.0.41"}