@newhomestar/sdk 0.2.6 → 0.2.7

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/index.d.ts CHANGED
@@ -4,6 +4,10 @@ export interface ActionDef<I extends ZodTypeAny, O extends ZodTypeAny> {
4
4
  input: I;
5
5
  output: O;
6
6
  handler: (input: z.infer<I>, ctx: ActionCtx) => Promise<z.infer<O>>;
7
+ fga?: {
8
+ resourceType: string;
9
+ relation: string;
10
+ };
7
11
  }
8
12
  export interface ActionCtx {
9
13
  jobId: string;
@@ -13,6 +17,10 @@ export declare function action<I extends ZodTypeAny, O extends ZodTypeAny>(cfg:
13
17
  name?: string;
14
18
  input: I;
15
19
  output: O;
20
+ fga?: {
21
+ resourceType: string;
22
+ relation: string;
23
+ };
16
24
  handler: (input: z.infer<I>, ctx: ActionCtx) => Promise<z.infer<O>>;
17
25
  }): ActionDef<I, O>;
18
26
  export interface WorkerDef {
@@ -38,3 +46,5 @@ export type { ZodTypeAny as SchemaAny, ZodTypeAny };
38
46
  export declare function runHttpServer(def: WorkerDef, opts?: {
39
47
  port?: number;
40
48
  }): void;
49
+ export { parseNovaSpec } from "./parseSpec";
50
+ export type { NovaSpec } from "./parseSpec";
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseNovaSpec = void 0;
6
7
  exports.action = action;
7
8
  exports.defineWorker = defineWorker;
8
9
  exports.enqueue = enqueue;
@@ -114,9 +115,11 @@ function runHttpServer(def, opts = {}) {
114
115
  app.use(body_parser_1.default.json());
115
116
  for (const [actionName, act] of Object.entries(def.actions)) {
116
117
  const route = `/${def.name}/${actionName}`;
117
- app.post(route, async (req, res) => {
118
+ // unified handler: parse JSON body or default to empty object
119
+ const handler = async (req, res) => {
118
120
  try {
119
- const input = act.input.parse(req.body);
121
+ const payload = req.body && typeof req.body === 'object' ? req.body : {};
122
+ const input = act.input.parse(payload);
120
123
  const ctx = { jobId: `http-${Date.now()}`, progress: () => { } };
121
124
  const out = await act.handler(input, ctx);
122
125
  act.output.parse(out);
@@ -125,10 +128,19 @@ function runHttpServer(def, opts = {}) {
125
128
  catch (err) {
126
129
  res.status(400).json({ error: err.message });
127
130
  }
128
- });
131
+ };
132
+ // POST /<worker>/<action>
133
+ app.post(route, handler);
134
+ // expose health under GET /health for liveness checks
135
+ if (actionName === 'health') {
136
+ app.get(`/${actionName}`, handler);
137
+ }
129
138
  }
130
139
  const port = opts.port ?? (process.env.PORT ? parseInt(process.env.PORT) : 3000);
131
140
  app.listen(port, () => {
132
141
  console.log(`[nova] HTTP server listening on http://localhost:${port}`);
133
142
  });
134
143
  }
144
+ // YAML spec parsing utility
145
+ var parseSpec_1 = require("./parseSpec");
146
+ Object.defineProperty(exports, "parseNovaSpec", { enumerable: true, get: function () { return parseSpec_1.parseNovaSpec; } });
@@ -0,0 +1,444 @@
1
+ import { z } from "zod";
2
+ export declare const NovaSpecSchema: z.ZodObject<{
3
+ apiVersion: z.ZodString;
4
+ kind: z.ZodString;
5
+ metadata: z.ZodObject<{
6
+ name: z.ZodString;
7
+ displayName: z.ZodOptional<z.ZodString>;
8
+ description: z.ZodOptional<z.ZodString>;
9
+ icon: z.ZodOptional<z.ZodString>;
10
+ tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ name: string;
13
+ displayName?: string | undefined;
14
+ description?: string | undefined;
15
+ icon?: string | undefined;
16
+ tags?: string[] | undefined;
17
+ }, {
18
+ name: string;
19
+ displayName?: string | undefined;
20
+ description?: string | undefined;
21
+ icon?: string | undefined;
22
+ tags?: string[] | undefined;
23
+ }>;
24
+ spec: z.ZodObject<{
25
+ runtime: z.ZodObject<{
26
+ type: z.ZodString;
27
+ image: z.ZodString;
28
+ resources: z.ZodObject<{
29
+ cpu: z.ZodString;
30
+ memory: z.ZodString;
31
+ }, "strip", z.ZodTypeAny, {
32
+ cpu: string;
33
+ memory: string;
34
+ }, {
35
+ cpu: string;
36
+ memory: string;
37
+ }>;
38
+ command: z.ZodArray<z.ZodString, "many">;
39
+ queue: z.ZodString;
40
+ port: z.ZodNumber;
41
+ envSpec: z.ZodOptional<z.ZodArray<z.ZodObject<{
42
+ name: z.ZodString;
43
+ value: z.ZodOptional<z.ZodString>;
44
+ secret: z.ZodOptional<z.ZodBoolean>;
45
+ default: z.ZodOptional<z.ZodString>;
46
+ }, "strip", z.ZodTypeAny, {
47
+ name: string;
48
+ value?: string | undefined;
49
+ secret?: boolean | undefined;
50
+ default?: string | undefined;
51
+ }, {
52
+ name: string;
53
+ value?: string | undefined;
54
+ secret?: boolean | undefined;
55
+ default?: string | undefined;
56
+ }>, "many">>;
57
+ }, "strip", z.ZodTypeAny, {
58
+ type: string;
59
+ image: string;
60
+ resources: {
61
+ cpu: string;
62
+ memory: string;
63
+ };
64
+ command: string[];
65
+ queue: string;
66
+ port: number;
67
+ envSpec?: {
68
+ name: string;
69
+ value?: string | undefined;
70
+ secret?: boolean | undefined;
71
+ default?: string | undefined;
72
+ }[] | undefined;
73
+ }, {
74
+ type: string;
75
+ image: string;
76
+ resources: {
77
+ cpu: string;
78
+ memory: string;
79
+ };
80
+ command: string[];
81
+ queue: string;
82
+ port: number;
83
+ envSpec?: {
84
+ name: string;
85
+ value?: string | undefined;
86
+ secret?: boolean | undefined;
87
+ default?: string | undefined;
88
+ }[] | undefined;
89
+ }>;
90
+ actions: z.ZodArray<z.ZodObject<{
91
+ name: z.ZodString;
92
+ displayName: z.ZodOptional<z.ZodString>;
93
+ description: z.ZodOptional<z.ZodString>;
94
+ icon: z.ZodOptional<z.ZodString>;
95
+ async: z.ZodOptional<z.ZodBoolean>;
96
+ input: z.ZodOptional<z.ZodUnknown>;
97
+ output: z.ZodOptional<z.ZodUnknown>;
98
+ schema: z.ZodOptional<z.ZodObject<{
99
+ input: z.ZodString;
100
+ output: z.ZodString;
101
+ }, "strip", z.ZodTypeAny, {
102
+ input: string;
103
+ output: string;
104
+ }, {
105
+ input: string;
106
+ output: string;
107
+ }>>;
108
+ fga: z.ZodOptional<z.ZodObject<{
109
+ resourceType: z.ZodString;
110
+ relation: z.ZodString;
111
+ }, "strip", z.ZodTypeAny, {
112
+ resourceType: string;
113
+ relation: string;
114
+ }, {
115
+ resourceType: string;
116
+ relation: string;
117
+ }>>;
118
+ }, "strip", z.ZodTypeAny, {
119
+ name: string;
120
+ displayName?: string | undefined;
121
+ description?: string | undefined;
122
+ icon?: string | undefined;
123
+ async?: boolean | undefined;
124
+ input?: unknown;
125
+ output?: unknown;
126
+ schema?: {
127
+ input: string;
128
+ output: string;
129
+ } | undefined;
130
+ fga?: {
131
+ resourceType: string;
132
+ relation: string;
133
+ } | undefined;
134
+ }, {
135
+ name: string;
136
+ displayName?: string | undefined;
137
+ description?: string | undefined;
138
+ icon?: string | undefined;
139
+ async?: boolean | undefined;
140
+ input?: unknown;
141
+ output?: unknown;
142
+ schema?: {
143
+ input: string;
144
+ output: string;
145
+ } | undefined;
146
+ fga?: {
147
+ resourceType: string;
148
+ relation: string;
149
+ } | undefined;
150
+ }>, "many">;
151
+ }, "strip", z.ZodTypeAny, {
152
+ runtime: {
153
+ type: string;
154
+ image: string;
155
+ resources: {
156
+ cpu: string;
157
+ memory: string;
158
+ };
159
+ command: string[];
160
+ queue: string;
161
+ port: number;
162
+ envSpec?: {
163
+ name: string;
164
+ value?: string | undefined;
165
+ secret?: boolean | undefined;
166
+ default?: string | undefined;
167
+ }[] | undefined;
168
+ };
169
+ actions: {
170
+ name: string;
171
+ displayName?: string | undefined;
172
+ description?: string | undefined;
173
+ icon?: string | undefined;
174
+ async?: boolean | undefined;
175
+ input?: unknown;
176
+ output?: unknown;
177
+ schema?: {
178
+ input: string;
179
+ output: string;
180
+ } | undefined;
181
+ fga?: {
182
+ resourceType: string;
183
+ relation: string;
184
+ } | undefined;
185
+ }[];
186
+ }, {
187
+ runtime: {
188
+ type: string;
189
+ image: string;
190
+ resources: {
191
+ cpu: string;
192
+ memory: string;
193
+ };
194
+ command: string[];
195
+ queue: string;
196
+ port: number;
197
+ envSpec?: {
198
+ name: string;
199
+ value?: string | undefined;
200
+ secret?: boolean | undefined;
201
+ default?: string | undefined;
202
+ }[] | undefined;
203
+ };
204
+ actions: {
205
+ name: string;
206
+ displayName?: string | undefined;
207
+ description?: string | undefined;
208
+ icon?: string | undefined;
209
+ async?: boolean | undefined;
210
+ input?: unknown;
211
+ output?: unknown;
212
+ schema?: {
213
+ input: string;
214
+ output: string;
215
+ } | undefined;
216
+ fga?: {
217
+ resourceType: string;
218
+ relation: string;
219
+ } | undefined;
220
+ }[];
221
+ }>;
222
+ build: z.ZodOptional<z.ZodObject<{
223
+ dockerfile: z.ZodString;
224
+ context: z.ZodString;
225
+ }, "strip", z.ZodTypeAny, {
226
+ dockerfile: string;
227
+ context: string;
228
+ }, {
229
+ dockerfile: string;
230
+ context: string;
231
+ }>>;
232
+ ui: z.ZodOptional<z.ZodObject<{
233
+ category: z.ZodOptional<z.ZodString>;
234
+ color: z.ZodOptional<z.ZodString>;
235
+ }, "strip", z.ZodTypeAny, {
236
+ category?: string | undefined;
237
+ color?: string | undefined;
238
+ }, {
239
+ category?: string | undefined;
240
+ color?: string | undefined;
241
+ }>>;
242
+ fga: z.ZodOptional<z.ZodObject<{
243
+ types: z.ZodArray<z.ZodObject<{
244
+ name: z.ZodString;
245
+ relations: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodObject<{
246
+ computedUserset: z.ZodObject<{
247
+ object: z.ZodString;
248
+ relation: z.ZodString;
249
+ }, "strip", z.ZodTypeAny, {
250
+ object: string;
251
+ relation: string;
252
+ }, {
253
+ object: string;
254
+ relation: string;
255
+ }>;
256
+ }, "strip", z.ZodTypeAny, {
257
+ computedUserset: {
258
+ object: string;
259
+ relation: string;
260
+ };
261
+ }, {
262
+ computedUserset: {
263
+ object: string;
264
+ relation: string;
265
+ };
266
+ }>]>>;
267
+ }, "strip", z.ZodTypeAny, {
268
+ name: string;
269
+ relations: Record<string, string[] | {
270
+ computedUserset: {
271
+ object: string;
272
+ relation: string;
273
+ };
274
+ }>;
275
+ }, {
276
+ name: string;
277
+ relations: Record<string, string[] | {
278
+ computedUserset: {
279
+ object: string;
280
+ relation: string;
281
+ };
282
+ }>;
283
+ }>, "many">;
284
+ }, "strip", z.ZodTypeAny, {
285
+ types: {
286
+ name: string;
287
+ relations: Record<string, string[] | {
288
+ computedUserset: {
289
+ object: string;
290
+ relation: string;
291
+ };
292
+ }>;
293
+ }[];
294
+ }, {
295
+ types: {
296
+ name: string;
297
+ relations: Record<string, string[] | {
298
+ computedUserset: {
299
+ object: string;
300
+ relation: string;
301
+ };
302
+ }>;
303
+ }[];
304
+ }>>;
305
+ }, "strict", z.ZodTypeAny, {
306
+ apiVersion: string;
307
+ kind: string;
308
+ metadata: {
309
+ name: string;
310
+ displayName?: string | undefined;
311
+ description?: string | undefined;
312
+ icon?: string | undefined;
313
+ tags?: string[] | undefined;
314
+ };
315
+ spec: {
316
+ runtime: {
317
+ type: string;
318
+ image: string;
319
+ resources: {
320
+ cpu: string;
321
+ memory: string;
322
+ };
323
+ command: string[];
324
+ queue: string;
325
+ port: number;
326
+ envSpec?: {
327
+ name: string;
328
+ value?: string | undefined;
329
+ secret?: boolean | undefined;
330
+ default?: string | undefined;
331
+ }[] | undefined;
332
+ };
333
+ actions: {
334
+ name: string;
335
+ displayName?: string | undefined;
336
+ description?: string | undefined;
337
+ icon?: string | undefined;
338
+ async?: boolean | undefined;
339
+ input?: unknown;
340
+ output?: unknown;
341
+ schema?: {
342
+ input: string;
343
+ output: string;
344
+ } | undefined;
345
+ fga?: {
346
+ resourceType: string;
347
+ relation: string;
348
+ } | undefined;
349
+ }[];
350
+ };
351
+ fga?: {
352
+ types: {
353
+ name: string;
354
+ relations: Record<string, string[] | {
355
+ computedUserset: {
356
+ object: string;
357
+ relation: string;
358
+ };
359
+ }>;
360
+ }[];
361
+ } | undefined;
362
+ build?: {
363
+ dockerfile: string;
364
+ context: string;
365
+ } | undefined;
366
+ ui?: {
367
+ category?: string | undefined;
368
+ color?: string | undefined;
369
+ } | undefined;
370
+ }, {
371
+ apiVersion: string;
372
+ kind: string;
373
+ metadata: {
374
+ name: string;
375
+ displayName?: string | undefined;
376
+ description?: string | undefined;
377
+ icon?: string | undefined;
378
+ tags?: string[] | undefined;
379
+ };
380
+ spec: {
381
+ runtime: {
382
+ type: string;
383
+ image: string;
384
+ resources: {
385
+ cpu: string;
386
+ memory: string;
387
+ };
388
+ command: string[];
389
+ queue: string;
390
+ port: number;
391
+ envSpec?: {
392
+ name: string;
393
+ value?: string | undefined;
394
+ secret?: boolean | undefined;
395
+ default?: string | undefined;
396
+ }[] | undefined;
397
+ };
398
+ actions: {
399
+ name: string;
400
+ displayName?: string | undefined;
401
+ description?: string | undefined;
402
+ icon?: string | undefined;
403
+ async?: boolean | undefined;
404
+ input?: unknown;
405
+ output?: unknown;
406
+ schema?: {
407
+ input: string;
408
+ output: string;
409
+ } | undefined;
410
+ fga?: {
411
+ resourceType: string;
412
+ relation: string;
413
+ } | undefined;
414
+ }[];
415
+ };
416
+ fga?: {
417
+ types: {
418
+ name: string;
419
+ relations: Record<string, string[] | {
420
+ computedUserset: {
421
+ object: string;
422
+ relation: string;
423
+ };
424
+ }>;
425
+ }[];
426
+ } | undefined;
427
+ build?: {
428
+ dockerfile: string;
429
+ context: string;
430
+ } | undefined;
431
+ ui?: {
432
+ category?: string | undefined;
433
+ color?: string | undefined;
434
+ } | undefined;
435
+ }>;
436
+ export type NovaSpec = z.infer<typeof NovaSpecSchema>;
437
+ /**
438
+ * Parse nova.yaml content and validate against the NovaSpec schema.
439
+ * Unknown fields are stripped; missing required fields throw an error.
440
+ * @param yamlContent String contents of a nova.yaml specification
441
+ * @returns Parsed NovaSpec object
442
+ * @throws Error with validation details if parsing or validation fail
443
+ */
444
+ export declare function parseNovaSpec(yamlContent: string): NovaSpec;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NovaSpecSchema = void 0;
4
+ exports.parseNovaSpec = parseNovaSpec;
5
+ const yaml_1 = require("yaml");
6
+ const zod_1 = require("zod");
7
+ // Zod schema for nova.yaml
8
+ exports.NovaSpecSchema = zod_1.z.object({
9
+ apiVersion: zod_1.z.string(),
10
+ kind: zod_1.z.string(),
11
+ metadata: zod_1.z.object({
12
+ name: zod_1.z.string(),
13
+ displayName: zod_1.z.string().optional(),
14
+ description: zod_1.z.string().optional(),
15
+ icon: zod_1.z.string().optional(),
16
+ tags: zod_1.z.array(zod_1.z.string()).optional(),
17
+ }),
18
+ spec: zod_1.z.object({
19
+ runtime: zod_1.z.object({
20
+ type: zod_1.z.string(),
21
+ image: zod_1.z.string(),
22
+ resources: zod_1.z.object({
23
+ cpu: zod_1.z.string(),
24
+ memory: zod_1.z.string(),
25
+ }),
26
+ command: zod_1.z.array(zod_1.z.string()),
27
+ queue: zod_1.z.string(),
28
+ port: zod_1.z.number(),
29
+ envSpec: zod_1.z.array(zod_1.z.object({
30
+ name: zod_1.z.string(),
31
+ value: zod_1.z.string().optional(),
32
+ secret: zod_1.z.boolean().optional(),
33
+ default: zod_1.z.string().optional(),
34
+ })).optional(),
35
+ }),
36
+ actions: zod_1.z.array(zod_1.z.object({
37
+ name: zod_1.z.string(),
38
+ displayName: zod_1.z.string().optional(),
39
+ description: zod_1.z.string().optional(),
40
+ icon: zod_1.z.string().optional(),
41
+ async: zod_1.z.boolean().optional(),
42
+ input: zod_1.z.unknown().optional(), // JSON schema object
43
+ output: zod_1.z.unknown().optional(), // JSON schema object
44
+ schema: zod_1.z.object({
45
+ input: zod_1.z.string(),
46
+ output: zod_1.z.string(),
47
+ }).optional(),
48
+ fga: zod_1.z.object({
49
+ resourceType: zod_1.z.string(),
50
+ relation: zod_1.z.string(),
51
+ }).optional(),
52
+ })),
53
+ }),
54
+ build: zod_1.z.object({
55
+ dockerfile: zod_1.z.string(),
56
+ context: zod_1.z.string(),
57
+ }).optional(),
58
+ ui: zod_1.z.object({
59
+ category: zod_1.z.string().optional(),
60
+ color: zod_1.z.string().optional(),
61
+ }).optional(),
62
+ // OpenFGA policy hints embedded in nova.yaml
63
+ fga: zod_1.z.object({
64
+ types: zod_1.z.array(zod_1.z.object({
65
+ name: zod_1.z.string(),
66
+ relations: zod_1.z.record(zod_1.z.string(), zod_1.z.union([
67
+ zod_1.z.array(zod_1.z.string()),
68
+ zod_1.z.object({
69
+ computedUserset: zod_1.z.object({
70
+ object: zod_1.z.string(),
71
+ relation: zod_1.z.string(),
72
+ }),
73
+ }),
74
+ ])),
75
+ })),
76
+ }).optional(),
77
+ }).strict();
78
+ /**
79
+ * Parse nova.yaml content and validate against the NovaSpec schema.
80
+ * Unknown fields are stripped; missing required fields throw an error.
81
+ * @param yamlContent String contents of a nova.yaml specification
82
+ * @returns Parsed NovaSpec object
83
+ * @throws Error with validation details if parsing or validation fail
84
+ */
85
+ function parseNovaSpec(yamlContent) {
86
+ let parsed;
87
+ try {
88
+ parsed = (0, yaml_1.parse)(yamlContent);
89
+ }
90
+ catch (e) {
91
+ throw new Error(`Failed to parse YAML content: ${e.message}`);
92
+ }
93
+ try {
94
+ return exports.NovaSpecSchema.parse(parsed);
95
+ }
96
+ catch (e) {
97
+ if (e instanceof zod_1.z.ZodError) {
98
+ const details = e.errors
99
+ .map(err => `Path '${err.path.join(".")}': ${err.message}`)
100
+ .join("; ");
101
+ throw new Error(`nova.yaml validation error(s): ${details}`);
102
+ }
103
+ throw e;
104
+ }
105
+ }
package/package.json CHANGED
@@ -1,35 +1,36 @@
1
- {
2
- "name": "@newhomestar/sdk",
3
- "version": "0.2.6",
4
- "description": "Type-safe SDK for building Nova pipelines (workers & functions)",
5
- "homepage": "https://github.com/newhomestar/nova-node-sdk#readme",
6
- "bugs": {
7
- "url": "https://github.com/newhomestar/nova-node-sdk/issues"
8
- },
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/newhomestar/nova-node-sdk.git"
12
- },
13
- "license": "ISC",
14
- "author": "Christian Gomez",
15
- "type": "commonjs",
16
- "main": "dist/index.js",
17
- "types": "dist/index.d.ts",
18
- "files": [
19
- "dist"
20
- ],
21
- "scripts": {
22
- "build": "tsc"
23
- },
24
- "dependencies": {
25
- "@supabase/supabase-js": "^2.39.0",
26
- "dotenv": "^16.4.3",
27
- "zod": "^3.23.8",
28
- "express": "^4.18.2",
29
- "body-parser": "^1.20.2"
30
- },
31
- "devDependencies": {
32
- "@types/node": "^20.11.17",
33
- "typescript": "^5.4.4"
34
- }
35
- }
1
+ {
2
+ "name": "@newhomestar/sdk",
3
+ "version": "0.2.7",
4
+ "description": "Type-safe SDK for building Nova pipelines (workers & functions)",
5
+ "homepage": "https://github.com/newhomestar/nova-node-sdk#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/newhomestar/nova-node-sdk/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/newhomestar/nova-node-sdk.git"
12
+ },
13
+ "license": "ISC",
14
+ "author": "Christian Gomez",
15
+ "type": "commonjs",
16
+ "main": "dist/index.js",
17
+ "types": "dist/index.d.ts",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc"
23
+ },
24
+ "dependencies": {
25
+ "@supabase/supabase-js": "^2.39.0",
26
+ "dotenv": "^16.4.3",
27
+ "zod": "^3.23.8",
28
+ "express": "^4.18.2",
29
+ "body-parser": "^1.20.2",
30
+ "yaml": "^2.7.1"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.11.17",
34
+ "typescript": "^5.4.4"
35
+ }
36
+ }