@nubbin/core 0.1.0-rc.0 → 0.1.0-rc.4

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/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # @nubbin/core
2
+
3
+ The contract every other Nubbin package is built around. It defines what a block is, keeps the
4
+ catalog and the registry apart, and compiles a page document into an immutable artifact.
5
+
6
+ It has one runtime dependency — [Standard Schema](https://standardschema.dev) — and imports no
7
+ validator, no framework and no node builtin. A build gate fails on any of the three, so the
8
+ claim that it runs in a browser, a worker and a build step is checked rather than asserted.
9
+
10
+ ```bash
11
+ npm install @nubbin/core@rc
12
+ ```
13
+
14
+ ```ts
15
+ import { defineBlock, defineCatalog, createRegistry, compile } from "@nubbin/core";
16
+ import { z } from "zod";
17
+
18
+ const heroSchema = z.object({ title: z.string() });
19
+
20
+ export const heroBlock = defineBlock({
21
+ name: "Hero",
22
+ schema: heroSchema,
23
+ component: Hero,
24
+ version: 1,
25
+ slots: {},
26
+ });
27
+
28
+ const artifact = compile(documentVersion, catalog, registry, "/promotions/summer");
29
+ ```
30
+
31
+ Props are inferred from the schema with `InferProps<typeof heroSchema>`, so nothing declares a
32
+ block's shape twice.
33
+
34
+ **Release candidate.** The API is settled enough to build against and not yet stable.
35
+
36
+ The design record, including the paths not taken, is at
37
+ <https://effekt.github.io/nubbin/>. MIT.
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ type UnknownProps = Record<string, unknown>;
11
11
  */
12
12
  type InferProps<Schema extends StandardSchemaV1> = StandardSchemaV1.InferOutput<Schema>;
13
13
  interface SlotConstraint {
14
- /** Block names permitted here. Omitted means any registered block. */
14
+ /** Block names permitted here, each resolved at registration. Omitted means any registered block. */
15
15
  allow?: readonly string[];
16
16
  min?: number;
17
17
  max?: number;
@@ -179,6 +179,9 @@ declare function compile(version: DocumentVersion, catalog: Catalog, registry: R
179
179
  * Sorted by name so registration order cannot change the fingerprint, and built from name and
180
180
  * version alone so unrelated edits — a slot constraint, a deprecation — do not invalidate every
181
181
  * artifact compiled before them.
182
+ *
183
+ * Slot `allow` lists resolve once the whole array is ingested, so a block may name a sibling
184
+ * registered after it.
182
185
  */
183
186
  declare function createRegistry(blocks: readonly Block[]): Registry;
184
187
 
package/dist/index.js CHANGED
@@ -401,7 +401,7 @@ function validateStructure(version, registry) {
401
401
  }
402
402
 
403
403
  // src/version.constants.ts
404
- var NUBBIN_VERSION = "0.0.0";
404
+ var NUBBIN_VERSION = "0.1.0-rc.4";
405
405
 
406
406
  // src/compile.ts
407
407
  function compile(version, catalog, registry, route) {
@@ -423,6 +423,24 @@ function compile(version, catalog, registry, route) {
423
423
  return { ...content, hash: hashArtifact(content) };
424
424
  }
425
425
 
426
+ // src/unknownAllowEntries.ts
427
+ function unknownAllowEntries(block, known) {
428
+ return Object.entries(block.slots).flatMap(
429
+ ([slot, constraint]) => (constraint.allow ?? []).filter((allowed) => !known.has(allowed)).map((allowed) => `"${allowed}" (${block.name}.${slot})`)
430
+ );
431
+ }
432
+
433
+ // src/assertSlotAllows.ts
434
+ function assertSlotAllows(blocks) {
435
+ const known = new Set(blocks.map((block) => block.name));
436
+ const unresolved = blocks.flatMap((block) => unknownAllowEntries(block, known));
437
+ if (unresolved.length > 0) {
438
+ throw new Error(
439
+ `Slot allow lists name ${unresolved.join(", ")}, which no registered block defines. Registered blocks: ${[...known].sort().join(", ")}`
440
+ );
441
+ }
442
+ }
443
+
426
444
  // src/createRegistry.ts
427
445
  function createRegistry(blocks) {
428
446
  const byName = /* @__PURE__ */ new Map();
@@ -434,6 +452,7 @@ function createRegistry(blocks) {
434
452
  }
435
453
  byName.set(block.name, block);
436
454
  }
455
+ assertSlotAllows([...byName.values()]);
437
456
  const signature = [...byName.values()].map((block) => `${block.name}@${block.version}`).sort().join("\n");
438
457
  const fingerprint = fnv1a(signature);
439
458
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nubbin/core",
3
- "version": "0.1.0-rc.0",
3
+ "version": "0.1.0-rc.4",
4
4
  "description": "The Nubbin contract: define blocks, split catalog from registry, and compile a page document into an immutable artifact.",
5
5
  "keywords": [
6
6
  "nubbin",