@notionhq/workers 0.5.0 → 0.6.0

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 (189) hide show
  1. package/dist/alpha/builder.d.ts +149 -0
  2. package/dist/alpha/builder.d.ts.map +1 -0
  3. package/dist/alpha/builder.js +260 -0
  4. package/dist/alpha/builder.test.d.ts +2 -0
  5. package/dist/alpha/builder.test.d.ts.map +1 -0
  6. package/dist/alpha/cli/build.d.ts +13 -0
  7. package/dist/alpha/cli/build.d.ts.map +1 -0
  8. package/dist/alpha/cli/build.js +36 -0
  9. package/dist/alpha/cli/build.test.d.ts +2 -0
  10. package/dist/alpha/cli/build.test.d.ts.map +1 -0
  11. package/dist/alpha/cli/codegen.d.ts +10 -0
  12. package/dist/alpha/cli/codegen.d.ts.map +1 -0
  13. package/dist/alpha/cli/codegen.js +41 -0
  14. package/dist/alpha/cli/codegen.test.d.ts +2 -0
  15. package/dist/alpha/cli/codegen.test.d.ts.map +1 -0
  16. package/dist/alpha/cli/discover.d.ts +35 -0
  17. package/dist/alpha/cli/discover.d.ts.map +1 -0
  18. package/dist/alpha/cli/discover.js +39 -0
  19. package/dist/alpha/cli/discover.test.d.ts +2 -0
  20. package/dist/alpha/cli/discover.test.d.ts.map +1 -0
  21. package/dist/alpha/cli/emit-manifest.d.ts +33 -0
  22. package/dist/alpha/cli/emit-manifest.d.ts.map +1 -0
  23. package/dist/alpha/cli/emit-manifest.js +266 -0
  24. package/dist/alpha/cli/emit-manifest.test.d.ts +2 -0
  25. package/dist/alpha/cli/emit-manifest.test.d.ts.map +1 -0
  26. package/dist/alpha/cli/index.d.ts +3 -0
  27. package/dist/alpha/cli/index.d.ts.map +1 -0
  28. package/dist/alpha/cli/index.js +36 -0
  29. package/dist/alpha/context.d.ts +8 -0
  30. package/dist/alpha/context.d.ts.map +1 -0
  31. package/dist/alpha/context.js +33 -0
  32. package/dist/alpha/database.d.ts +90 -0
  33. package/dist/alpha/database.d.ts.map +1 -0
  34. package/dist/alpha/database.js +9 -0
  35. package/dist/alpha/error.d.ts +41 -0
  36. package/dist/alpha/error.d.ts.map +1 -0
  37. package/dist/alpha/error.js +25 -0
  38. package/dist/alpha/icon-names.d.ts +6 -0
  39. package/dist/alpha/icon-names.d.ts.map +1 -0
  40. package/dist/alpha/icon-names.js +0 -0
  41. package/dist/alpha/json-schema.d.ts +117 -0
  42. package/dist/alpha/json-schema.d.ts.map +1 -0
  43. package/dist/alpha/json-schema.js +0 -0
  44. package/dist/alpha/manifest.d.ts +44 -0
  45. package/dist/alpha/manifest.d.ts.map +1 -0
  46. package/dist/alpha/manifest.js +0 -0
  47. package/dist/alpha/output.d.ts +7 -0
  48. package/dist/alpha/output.d.ts.map +1 -0
  49. package/dist/alpha/output.js +8 -0
  50. package/dist/alpha/pacer.d.ts +74 -0
  51. package/dist/alpha/pacer.d.ts.map +1 -0
  52. package/dist/alpha/pacer.js +66 -0
  53. package/dist/alpha/pacer.test.d.ts +2 -0
  54. package/dist/alpha/pacer.test.d.ts.map +1 -0
  55. package/dist/alpha/schedule.d.ts +6 -0
  56. package/dist/alpha/schedule.d.ts.map +1 -0
  57. package/dist/alpha/schedule.js +43 -0
  58. package/dist/alpha/schedule.test.d.ts +2 -0
  59. package/dist/alpha/schedule.test.d.ts.map +1 -0
  60. package/dist/alpha/schema-builder.d.ts +79 -0
  61. package/dist/alpha/schema-builder.d.ts.map +1 -0
  62. package/dist/alpha/schema-builder.js +135 -0
  63. package/dist/alpha/schema.d.ts +185 -0
  64. package/dist/alpha/schema.d.ts.map +1 -0
  65. package/dist/alpha/schema.js +115 -0
  66. package/dist/alpha/sync.d.ts +233 -0
  67. package/dist/alpha/sync.d.ts.map +1 -0
  68. package/dist/alpha/sync.js +70 -0
  69. package/dist/alpha/sync.test.d.ts +2 -0
  70. package/dist/alpha/sync.test.d.ts.map +1 -0
  71. package/dist/alpha/tool.d.ts +132 -0
  72. package/dist/alpha/tool.d.ts.map +1 -0
  73. package/dist/alpha/tool.js +156 -0
  74. package/dist/alpha/tool.test.d.ts +2 -0
  75. package/dist/alpha/tool.test.d.ts.map +1 -0
  76. package/dist/alpha/triggers.d.ts +365 -0
  77. package/dist/alpha/triggers.d.ts.map +1 -0
  78. package/dist/alpha/triggers.generated.d.ts +246 -0
  79. package/dist/alpha/triggers.generated.d.ts.map +1 -0
  80. package/dist/alpha/triggers.generated.js +239 -0
  81. package/dist/alpha/triggers.js +0 -0
  82. package/dist/alpha/types.d.ts +228 -0
  83. package/dist/alpha/types.d.ts.map +1 -0
  84. package/dist/alpha/types.js +0 -0
  85. package/dist/alpha/workflow.d.ts +70 -0
  86. package/dist/alpha/workflow.d.ts.map +1 -0
  87. package/dist/alpha/workflow.js +39 -0
  88. package/dist/alpha/workflow.test.d.ts +2 -0
  89. package/dist/alpha/workflow.test.d.ts.map +1 -0
  90. package/dist/builder.d.ts.map +1 -1
  91. package/dist/builder.js +2 -6
  92. package/dist/capabilities/ai_connector.d.ts.map +1 -1
  93. package/dist/capabilities/automation.d.ts.map +1 -1
  94. package/dist/capabilities/context.d.ts.map +1 -1
  95. package/dist/capabilities/custom-block.d.ts +124 -0
  96. package/dist/capabilities/custom-block.d.ts.map +1 -0
  97. package/dist/capabilities/custom-block.js +22 -0
  98. package/dist/capabilities/oauth.d.ts.map +1 -1
  99. package/dist/capabilities/output.d.ts.map +1 -1
  100. package/dist/capabilities/output.js +2 -4
  101. package/dist/capabilities/stateful-capability.d.ts.map +1 -1
  102. package/dist/capabilities/stateful-capability.js +2 -6
  103. package/dist/capabilities/sync.d.ts.map +1 -1
  104. package/dist/capabilities/sync.js +2 -8
  105. package/dist/capabilities/tool.d.ts.map +1 -1
  106. package/dist/capabilities/tool.js +6 -20
  107. package/dist/capabilities/webhook.d.ts.map +1 -1
  108. package/dist/capabilities/workflow.d.ts +2 -2
  109. package/dist/capabilities/workflow.d.ts.map +1 -1
  110. package/dist/index.d.ts +3 -2
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +1 -7
  113. package/dist/json-schema.d.ts.map +1 -1
  114. package/dist/schema-builder.d.ts.map +1 -1
  115. package/dist/schema.d.ts.map +1 -1
  116. package/dist/types.d.ts.map +1 -1
  117. package/dist/worker.d.ts +41 -1
  118. package/dist/worker.d.ts.map +1 -1
  119. package/dist/worker.js +51 -4
  120. package/package.json +74 -14
  121. package/src/alpha/ajv-formats.d.ts +7 -0
  122. package/src/alpha/builder.test.ts +197 -0
  123. package/src/alpha/builder.ts +338 -0
  124. package/src/alpha/cli/build.test.ts +240 -0
  125. package/src/alpha/cli/build.ts +57 -0
  126. package/src/alpha/cli/codegen.test.ts +31 -0
  127. package/src/alpha/cli/codegen.ts +51 -0
  128. package/src/alpha/cli/discover.test.ts +43 -0
  129. package/src/alpha/cli/discover.ts +81 -0
  130. package/src/alpha/cli/emit-manifest.test.ts +45 -0
  131. package/src/alpha/cli/emit-manifest.ts +409 -0
  132. package/src/alpha/cli/index.ts +41 -0
  133. package/src/alpha/context.ts +61 -0
  134. package/src/alpha/database.ts +102 -0
  135. package/src/alpha/error.ts +49 -0
  136. package/src/alpha/icon-names.ts +890 -0
  137. package/src/alpha/json-schema.ts +180 -0
  138. package/src/alpha/manifest.ts +47 -0
  139. package/src/alpha/output.ts +8 -0
  140. package/src/alpha/pacer.test.ts +81 -0
  141. package/src/alpha/pacer.ts +181 -0
  142. package/src/alpha/schedule.test.ts +31 -0
  143. package/src/alpha/schedule.ts +53 -0
  144. package/src/alpha/schema-builder.ts +193 -0
  145. package/src/alpha/schema.ts +222 -0
  146. package/src/alpha/sync.test.ts +191 -0
  147. package/src/alpha/sync.ts +340 -0
  148. package/src/alpha/tool.test.ts +116 -0
  149. package/src/alpha/tool.ts +319 -0
  150. package/src/alpha/triggers.generated.ts +489 -0
  151. package/src/alpha/triggers.ts +500 -0
  152. package/src/alpha/types.ts +284 -0
  153. package/src/alpha/workflow.test.ts +84 -0
  154. package/src/alpha/workflow.ts +131 -0
  155. package/src/builder.test.ts +28 -60
  156. package/src/builder.ts +3 -10
  157. package/src/capabilities/ai_connector.test.ts +9 -32
  158. package/src/capabilities/ai_connector.ts +5 -17
  159. package/src/capabilities/automation.test.ts +3 -12
  160. package/src/capabilities/automation.ts +3 -11
  161. package/src/capabilities/context.ts +3 -6
  162. package/src/capabilities/custom-block.ts +181 -0
  163. package/src/capabilities/oauth.test.ts +1 -0
  164. package/src/capabilities/oauth.ts +1 -3
  165. package/src/capabilities/output.ts +1 -3
  166. package/src/capabilities/stateful-capability.test.ts +1 -0
  167. package/src/capabilities/stateful-capability.ts +2 -6
  168. package/src/capabilities/sync.test.ts +15 -45
  169. package/src/capabilities/sync.ts +10 -40
  170. package/src/capabilities/tool.test.ts +106 -146
  171. package/src/capabilities/tool.ts +17 -39
  172. package/src/capabilities/webhook.ts +3 -10
  173. package/src/capabilities/workflow.test.ts +10 -31
  174. package/src/capabilities/workflow.ts +5 -12
  175. package/src/index.ts +9 -12
  176. package/src/json-schema.test.ts +2 -4
  177. package/src/json-schema.ts +7 -6
  178. package/src/pacer.test.ts +1 -3
  179. package/src/pacer_internal.ts +1 -5
  180. package/src/schema-builder.test.ts +10 -35
  181. package/src/schema-builder.ts +5 -16
  182. package/src/schema.ts +2 -10
  183. package/src/types.ts +1 -7
  184. package/src/worker.test.ts +147 -0
  185. package/src/worker.ts +67 -35
  186. package/dist/block.d.ts +0 -321
  187. package/dist/block.d.ts.map +0 -1
  188. package/src/block.ts +0 -529
  189. /package/dist/{block.js → alpha/ajv-formats.d.js} +0 -0
@@ -1,19 +1,7 @@
1
- import {
2
- afterEach,
3
- beforeEach,
4
- describe,
5
- expect,
6
- expectTypeOf,
7
- it,
8
- type Mock,
9
- vi,
10
- } from "vitest";
1
+ import { afterEach, beforeEach, describe, expect, expectTypeOf, it, type Mock, vi } from "vitest";
2
+
11
3
  import { ExecutionError } from "../error.js";
12
- import {
13
- type CapabilityContext,
14
- Worker,
15
- type WorkflowConfiguration,
16
- } from "../index.js";
4
+ import { type CapabilityContext, Worker, type WorkflowConfiguration } from "../index.js";
17
5
  import {
18
6
  type NotionPageCreatedEvent,
19
7
  type NotionPageCreatedTrigger,
@@ -66,9 +54,7 @@ describe("createWorkflowCapability", () => {
66
54
  let stdoutSpy: Mock<typeof process.stdout.write>;
67
55
 
68
56
  beforeEach(() => {
69
- stdoutSpy = vi
70
- .spyOn(process.stdout, "write")
71
- .mockImplementation(() => true);
57
+ stdoutSpy = vi.spyOn(process.stdout, "write").mockImplementation(() => true);
72
58
  });
73
59
 
74
60
  afterEach(() => {
@@ -82,13 +68,8 @@ describe("createWorkflowCapability", () => {
82
68
  });
83
69
 
84
70
  it("requires trigger declarations in workflow configuration", () => {
85
- type PageAddedConfiguration = WorkflowConfiguration<
86
- readonly [NotionPageCreatedTrigger]
87
- >;
88
- type ConfigurationWithoutTriggers = Omit<
89
- PageAddedConfiguration,
90
- "triggers"
91
- >;
71
+ type PageAddedConfiguration = WorkflowConfiguration<readonly [NotionPageCreatedTrigger]>;
72
+ type ConfigurationWithoutTriggers = Omit<PageAddedConfiguration, "triggers">;
92
73
 
93
74
  expectTypeOf<ConfigurationWithoutTriggers>().not.toMatchTypeOf<PageAddedConfiguration>();
94
75
  });
@@ -137,9 +118,9 @@ describe("createWorkflowCapability", () => {
137
118
  execute,
138
119
  });
139
120
 
140
- await expect(
141
- capability.handler(pageCreatedEvent, { concreteOutput: true }),
142
- ).resolves.toEqual({ status: "success" });
121
+ await expect(capability.handler(pageCreatedEvent, { concreteOutput: true })).resolves.toEqual({
122
+ status: "success",
123
+ });
143
124
  expect(execute).toHaveBeenCalledWith(
144
125
  pageCreatedEvent,
145
126
  expect.objectContaining({ notion: expect.any(Object) }),
@@ -172,9 +153,7 @@ describe("createWorkflowCapability", () => {
172
153
  },
173
154
  });
174
155
 
175
- await expect(capability.handler(pageCreatedEvent)).rejects.toThrow(
176
- ExecutionError,
177
- );
156
+ await expect(capability.handler(pageCreatedEvent)).rejects.toThrow(ExecutionError);
178
157
  expect(stdoutSpy).toHaveBeenCalledWith(
179
158
  expect.stringContaining(
180
159
  '"_tag":"error","error":{"name":"ExecutionError","message":"Error during worker execution: Error: Something went wrong"',
@@ -1,8 +1,5 @@
1
1
  import { ExecutionError } from "../error.js";
2
- import type {
3
- WorkflowEventMap,
4
- WorkflowTrigger,
5
- } from "../triggers.generated.js";
2
+ import type { WorkflowEventMap, WorkflowTrigger } from "../triggers.generated.js";
6
3
  import type { HandlerOptions } from "../types.js";
7
4
  import type { CapabilityContext } from "./context.js";
8
5
  import { createCapabilityContext } from "./context.js";
@@ -10,8 +7,7 @@ import { writeOutput } from "./output.js";
10
7
 
11
8
  export type WorkflowEvent = WorkflowEventMap[keyof WorkflowEventMap];
12
9
 
13
- export type WorkflowEventForTrigger<T extends WorkflowTrigger> =
14
- WorkflowEventMap[T["type"]];
10
+ export type WorkflowEventForTrigger<T extends WorkflowTrigger> = WorkflowEventMap[T["type"]];
15
11
 
16
12
  export type WorkflowEventForTriggers<T extends readonly WorkflowTrigger[]> =
17
13
  WorkflowEventForTrigger<T[number]>;
@@ -46,10 +42,10 @@ export type WorkflowConfiguration<
46
42
  };
47
43
 
48
44
  export type WorkflowCapability<
49
- TTriggers extends readonly [
45
+ TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]] = readonly [
50
46
  WorkflowTrigger,
51
47
  ...WorkflowTrigger[],
52
- ] = readonly [WorkflowTrigger, ...WorkflowTrigger[]],
48
+ ],
53
49
  > = {
54
50
  _tag: "workflow";
55
51
  key: string;
@@ -73,10 +69,7 @@ export type WorkflowCapability<
73
69
  */
74
70
  export function createWorkflowCapability<
75
71
  const TTriggers extends readonly [WorkflowTrigger, ...WorkflowTrigger[]],
76
- >(
77
- key: string,
78
- config: WorkflowConfiguration<TTriggers>,
79
- ): WorkflowCapability<TTriggers> {
72
+ >(key: string, config: WorkflowConfiguration<TTriggers>): WorkflowCapability<TTriggers> {
80
73
  return {
81
74
  _tag: "workflow",
82
75
  key,
package/src/index.ts CHANGED
@@ -1,10 +1,11 @@
1
- export {
2
- emojiIcon,
3
- imageCover,
4
- imageIcon,
5
- notionIcon,
6
- place,
7
- } from "./builder.js";
1
+ export type {
2
+ CustomBlockCapability,
3
+ CustomBlockCapabilityConfig,
4
+ CustomBlockConfiguration,
5
+ CustomBlockManifest,
6
+ CustomBlockManifestDataSource,
7
+ } from "./capabilities/custom-block.js";
8
+ export { emojiIcon, imageCover, imageIcon, notionIcon, place } from "./builder.js";
8
9
  export type {
9
10
  AiConnectorArchetype,
10
11
  AiConnectorCapability,
@@ -43,11 +44,7 @@ export type {
43
44
  SyncExecutionResult,
44
45
  SyncMode,
45
46
  } from "./capabilities/sync.js";
46
- export type {
47
- ToolCapability,
48
- ToolConfiguration,
49
- ToolHints,
50
- } from "./capabilities/tool.js";
47
+ export type { ToolCapability, ToolConfiguration, ToolHints } from "./capabilities/tool.js";
51
48
  export type {
52
49
  WebhookCapability,
53
50
  WebhookConfiguration,
@@ -12,6 +12,7 @@
12
12
  * This ensures tsc sees the error on the line immediately after the directive.
13
13
  */
14
14
  import { describe, expect, it } from "vitest";
15
+
15
16
  import type {
16
17
  AnyJSONSchema,
17
18
  JSONSchema,
@@ -671,10 +672,7 @@ describe("JSONSchema — complex schemas", () => {
671
672
 
672
673
  describe("JSONSchema — structural type assertions", () => {
673
674
  it("JSONSchemaObjectDef requires additionalProperties to be false", () => {
674
- type _Proof = Assert<
675
- JSONSchemaObjectDef<{ x: number }>["additionalProperties"],
676
- false
677
- >;
675
+ type _Proof = Assert<JSONSchemaObjectDef<{ x: number }>["additionalProperties"], false>;
678
676
  });
679
677
 
680
678
  it("JSONSchemaArrayDef minItems is restricted to 0 | 1", () => {
@@ -45,16 +45,18 @@ interface ForbiddenCompositionKeywords {
45
45
 
46
46
  // ---- Individual schema definitions ----
47
47
 
48
- export interface JSONSchemaStringDef<T extends string = string>
49
- extends ForbiddenCompositionKeywords {
48
+ export interface JSONSchemaStringDef<
49
+ T extends string = string,
50
+ > extends ForbiddenCompositionKeywords {
50
51
  type: "string";
51
52
  description?: string;
52
53
  format?: JSONSchemaStringFormat;
53
54
  enum?: readonly T[];
54
55
  }
55
56
 
56
- export interface JSONSchemaNumberDef<T extends number = number>
57
- extends ForbiddenCompositionKeywords {
57
+ export interface JSONSchemaNumberDef<
58
+ T extends number = number,
59
+ > extends ForbiddenCompositionKeywords {
58
60
  type: "number" | "integer";
59
61
  description?: string;
60
62
  enum?: readonly T[];
@@ -70,8 +72,7 @@ export interface JSONSchemaNullDef extends ForbiddenCompositionKeywords {
70
72
  description?: string;
71
73
  }
72
74
 
73
- export interface JSONSchemaArrayDef<E = unknown>
74
- extends ForbiddenCompositionKeywords {
75
+ export interface JSONSchemaArrayDef<E = unknown> extends ForbiddenCompositionKeywords {
75
76
  type: "array";
76
77
  description?: string;
77
78
  items: JSONSchema<E>;
package/src/pacer.test.ts CHANGED
@@ -83,9 +83,7 @@ describe("pacerWait", () => {
83
83
  it("throws when pacer key not found in runtime context", async () => {
84
84
  setPacerState({ pacers: {} });
85
85
 
86
- await expect(pacerWait("unknown")).rejects.toThrow(
87
- 'Pacer "unknown" not found',
88
- );
86
+ await expect(pacerWait("unknown")).rejects.toThrow('Pacer "unknown" not found');
89
87
  });
90
88
 
91
89
  it("preserves allowedRequests and intervalMs across calls", async () => {
@@ -39,11 +39,7 @@ export function initPacerState(
39
39
  declarations?: readonly PacerDeclaration[],
40
40
  ): void {
41
41
  const pacers = runtimePacers ?? {};
42
- if (
43
- Object.keys(pacers).length === 0 &&
44
- declarations &&
45
- declarations.length > 0
46
- ) {
42
+ if (Object.keys(pacers).length === 0 && declarations && declarations.length > 0) {
47
43
  const localPacers: Record<string, PacerEntry> = {};
48
44
  for (const decl of declarations) {
49
45
  localPacers[decl.key] = {
@@ -1,11 +1,7 @@
1
1
  import { describe, expect, it } from "vitest";
2
+
2
3
  import type { JSONSchema } from "./json-schema.js";
3
- import {
4
- getSchema,
5
- type Infer,
6
- j,
7
- type SchemaBuilder,
8
- } from "./schema-builder.js";
4
+ import { getSchema, type Infer, j, type SchemaBuilder } from "./schema-builder.js";
9
5
 
10
6
  // ---------------------------------------------------------------------------
11
7
  // 1. Primitives
@@ -188,9 +184,7 @@ describe("json-schema-builder — array", () => {
188
184
  });
189
185
 
190
186
  it("array of objects", () => {
191
- const schema = getSchema(
192
- j.array(j.object({ name: j.string(), age: j.number() })),
193
- );
187
+ const schema = getSchema(j.array(j.object({ name: j.string(), age: j.number() })));
194
188
  expect(schema).toEqual({
195
189
  type: "array",
196
190
  items: {
@@ -351,9 +345,7 @@ describe("json-schema-builder — anyOf", () => {
351
345
  });
352
346
 
353
347
  it("anyOf with description", () => {
354
- expect(
355
- getSchema(j.anyOf(j.string(), j.number()).describe("string or number")),
356
- ).toEqual({
348
+ expect(getSchema(j.anyOf(j.string(), j.number()).describe("string or number"))).toEqual({
357
349
  anyOf: [{ type: "string" }, { type: "number" }],
358
350
  description: "string or number",
359
351
  });
@@ -463,12 +455,8 @@ describe("json-schema-builder — discriminated unions", () => {
463
455
 
464
456
  it("discriminated union with descriptions on individual variants", () => {
465
457
  const schema = j.anyOf(
466
- j
467
- .object({ type: j.enum("text"), value: j.string() })
468
- .describe("A text node"),
469
- j
470
- .object({ type: j.enum("image"), url: j.string() })
471
- .describe("An image node"),
458
+ j.object({ type: j.enum("text"), value: j.string() }).describe("A text node"),
459
+ j.object({ type: j.enum("image"), url: j.string() }).describe("An image node"),
472
460
  );
473
461
 
474
462
  const raw = getSchema(schema) as unknown as {
@@ -497,9 +485,7 @@ describe("json-schema-builder — discriminated unions", () => {
497
485
  expect(raw.properties.content.anyOf).toHaveLength(2);
498
486
 
499
487
  // The content field is in required
500
- expect(
501
- (getSchema(schema) as unknown as Record<string, unknown>).required,
502
- ).toContain("content");
488
+ expect((getSchema(schema) as unknown as Record<string, unknown>).required).toContain("content");
503
489
  });
504
490
 
505
491
  it("nullable discriminated union", () => {
@@ -614,15 +600,7 @@ describe("json-schema-builder — integration", () => {
614
600
  },
615
601
  createdAt: { type: "string", format: "date-time" },
616
602
  },
617
- required: [
618
- "foo",
619
- "bar",
620
- "count",
621
- "tags",
622
- "address",
623
- "nickname",
624
- "createdAt",
625
- ],
603
+ required: ["foo", "bar", "count", "tags", "address", "nickname", "createdAt"],
626
604
  additionalProperties: false,
627
605
  });
628
606
  });
@@ -634,9 +612,7 @@ describe("json-schema-builder — integration", () => {
634
612
 
635
613
  describe("json-schema-builder — constraint enforcement", () => {
636
614
  it("object always has required matching properties keys", () => {
637
- const schema = getSchema(
638
- j.object({ x: j.number(), y: j.string(), z: j.boolean() }),
639
- );
615
+ const schema = getSchema(j.object({ x: j.number(), y: j.string(), z: j.boolean() }));
640
616
  const raw = schema as unknown as Record<string, unknown>;
641
617
  expect(raw.required).toEqual(["x", "y", "z"]);
642
618
  expect(raw.additionalProperties).toBe(false);
@@ -669,8 +645,7 @@ describe("json-schema-builder — constraint enforcement", () => {
669
645
  }),
670
646
  );
671
647
  const raw = schema as unknown as Record<string, unknown>;
672
- const outer = (raw as { properties: { outer: Record<string, unknown> } })
673
- .properties.outer;
648
+ const outer = (raw as { properties: { outer: Record<string, unknown> } }).properties.outer;
674
649
  expect(outer.required).toEqual(["inner"]);
675
650
  expect(outer.additionalProperties).toBe(false);
676
651
  });
@@ -47,12 +47,8 @@ function makeBuilder<T>(schema: AnyJSONSchema): SchemaBuilder<T> {
47
47
  return makeBuilder<T>({ ...schema, description: text });
48
48
  },
49
49
  nullable() {
50
- const { description: desc, ...rest } = schema as unknown as Record<
51
- string,
52
- unknown
53
- >;
54
- const inner =
55
- desc !== undefined ? (rest as unknown as AnyJSONSchema) : schema;
50
+ const { description: desc, ...rest } = schema as unknown as Record<string, unknown>;
51
+ const inner = desc !== undefined ? (rest as unknown as AnyJSONSchema) : schema;
56
52
  const wrapper: Record<string, unknown> = {
57
53
  anyOf: [inner, { type: "null" }],
58
54
  };
@@ -82,15 +78,9 @@ export function boolean(): SchemaBuilder<boolean> {
82
78
 
83
79
  // ---- Enum ----
84
80
 
85
- function enumBuilder<T extends string>(
86
- ...values: readonly T[]
87
- ): SchemaBuilder<T>;
88
- function enumBuilder<T extends number>(
89
- ...values: readonly T[]
90
- ): SchemaBuilder<T>;
91
- function enumBuilder(
92
- ...values: readonly (string | number)[]
93
- ): SchemaBuilder<unknown> {
81
+ function enumBuilder<T extends string>(...values: readonly T[]): SchemaBuilder<T>;
82
+ function enumBuilder<T extends number>(...values: readonly T[]): SchemaBuilder<T>;
83
+ function enumBuilder(...values: readonly (string | number)[]): SchemaBuilder<unknown> {
94
84
  const type = typeof values[0] === "string" ? "string" : "number";
95
85
  return makeBuilder({ type, enum: values } as AnyJSONSchema);
96
86
  }
@@ -155,7 +145,6 @@ export function object<P extends Record<string, SchemaBuilder<unknown>>>(
155
145
  const schemaProps: Record<string, AnyJSONSchema> = {};
156
146
  const keys = Object.keys(properties);
157
147
  for (const key of keys) {
158
- // biome-ignore lint/style/noNonNullAssertion: key comes from Object.keys(properties)
159
148
  schemaProps[key] = getSchema(properties[key]!);
160
149
  }
161
150
  return makeBuilder({
package/src/schema.ts CHANGED
@@ -1,10 +1,4 @@
1
- import type {
2
- DateFormat,
3
- Icon,
4
- NumberFormat,
5
- SelectOption,
6
- StatusGroup,
7
- } from "./types.js";
1
+ import type { DateFormat, Icon, NumberFormat, SelectOption, StatusGroup } from "./types.js";
8
2
 
9
3
  /**
10
4
  * Supported property types for sync schemas.
@@ -182,9 +176,7 @@ export function multiSelect(options: SelectOption[]): PropertyConfiguration {
182
176
  /**
183
177
  * Creates a status property definition with groups.
184
178
  */
185
- export function status(config: {
186
- groups: StatusGroup[];
187
- }): PropertyConfiguration {
179
+ export function status(config: { groups: StatusGroup[] }): PropertyConfiguration {
188
180
  return { type: "status", groups: config.groups };
189
181
  }
190
182
 
package/src/types.ts CHANGED
@@ -118,13 +118,7 @@ export type NumberFormat =
118
118
  /**
119
119
  * Date format types
120
120
  */
121
- export type DateFormat =
122
- | "relative"
123
- | "MM/DD/YYYY"
124
- | "DD/MM/YYYY"
125
- | "YYYY/MM/DD"
126
- | "ll"
127
- | "MMM d";
121
+ export type DateFormat = "relative" | "MM/DD/YYYY" | "DD/MM/YYYY" | "YYYY/MM/DD" | "ll" | "MMM d";
128
122
 
129
123
  import type { NoticonName } from "./icon-names.js";
130
124
 
@@ -141,6 +141,153 @@ describe("Worker", () => {
141
141
  ]);
142
142
  });
143
143
 
144
+ it("registers a project custom block from a folder path (type defaults to project)", () => {
145
+ const worker = new Worker();
146
+
147
+ worker.customBlock("visualBlock", {
148
+ path: "./views/visual",
149
+ });
150
+
151
+ expect(worker.manifest.capabilities).toEqual([
152
+ {
153
+ _tag: "custom_block",
154
+ key: "visualBlock",
155
+ config: {
156
+ source: { type: "project", path: "./views/visual" },
157
+ manifest: {
158
+ version: 1,
159
+ dataSources: {},
160
+ },
161
+ },
162
+ },
163
+ ]);
164
+ });
165
+
166
+ it("carries a project's custom build command and output dir", () => {
167
+ const worker = new Worker();
168
+
169
+ worker.customBlock("built", {
170
+ path: "./app",
171
+ command: "npm run build-prod",
172
+ output: "build",
173
+ });
174
+
175
+ expect(worker.manifest.capabilities).toEqual([
176
+ {
177
+ _tag: "custom_block",
178
+ key: "built",
179
+ config: {
180
+ source: {
181
+ type: "project",
182
+ path: "./app",
183
+ command: "npm run build-prod",
184
+ output: "build",
185
+ },
186
+ manifest: { version: 1, dataSources: {} },
187
+ },
188
+ },
189
+ ]);
190
+ });
191
+
192
+ it("registers a static custom block served as-is", () => {
193
+ const worker = new Worker();
194
+
195
+ worker.customBlock("prebuilt", { type: "static", path: "./dist" });
196
+
197
+ expect(worker.manifest.capabilities).toEqual([
198
+ {
199
+ _tag: "custom_block",
200
+ key: "prebuilt",
201
+ config: {
202
+ source: { type: "static", path: "./dist" },
203
+ manifest: { version: 1, dataSources: {} },
204
+ },
205
+ },
206
+ ]);
207
+ });
208
+
209
+ it("carries the author-declared data-source schema verbatim into the manifest", () => {
210
+ const worker = new Worker();
211
+
212
+ worker.customBlock("issueBoard", {
213
+ path: "./views/issueBoard",
214
+ dataSources: {
215
+ issues: {
216
+ name: "Issues",
217
+ description: "The team's issues",
218
+ icon: { type: "emoji", emoji: "🐛" },
219
+ properties: {
220
+ title: { name: "Title", type: "title" },
221
+ status: {
222
+ name: "Status",
223
+ description: "Workflow state",
224
+ type: "status",
225
+ },
226
+ },
227
+ },
228
+ },
229
+ });
230
+
231
+ expect(worker.manifest.capabilities).toEqual([
232
+ {
233
+ _tag: "custom_block",
234
+ key: "issueBoard",
235
+ config: {
236
+ source: { type: "project", path: "./views/issueBoard" },
237
+ manifest: {
238
+ version: 1,
239
+ dataSources: {
240
+ issues: {
241
+ name: "Issues",
242
+ description: "The team's issues",
243
+ icon: { type: "emoji", emoji: "🐛" },
244
+ properties: {
245
+ title: { name: "Title", type: "title" },
246
+ status: {
247
+ name: "Status",
248
+ description: "Workflow state",
249
+ type: "status",
250
+ },
251
+ },
252
+ },
253
+ },
254
+ },
255
+ },
256
+ },
257
+ ]);
258
+ });
259
+
260
+ it("threads a top-level manifest version into the generated manifest", () => {
261
+ const worker = new Worker();
262
+
263
+ worker.customBlock("versioned", {
264
+ path: "./views/versioned",
265
+ version: 1,
266
+ });
267
+
268
+ expect(worker.manifest.capabilities).toEqual([
269
+ {
270
+ _tag: "custom_block",
271
+ key: "versioned",
272
+ config: {
273
+ source: { type: "project", path: "./views/versioned" },
274
+ manifest: { version: 1, dataSources: {} },
275
+ },
276
+ },
277
+ ]);
278
+ });
279
+
280
+ it("cannot run a custom block capability", async () => {
281
+ const worker = new Worker();
282
+ worker.customBlock("visualBlock", {
283
+ path: "./views/visual",
284
+ });
285
+
286
+ await expect(worker.run("visualBlock", {})).rejects.toThrow(
287
+ 'Cannot run custom block capability "visualBlock"',
288
+ );
289
+ });
290
+
144
291
  it("rejects duplicate keys across databases, pacers, and capabilities", () => {
145
292
  const worker = new Worker();
146
293
  const db = worker.database("shared-key", {