@sequenceholdings/artifact-studio 0.5.0 → 0.6.2

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 (65) hide show
  1. package/README.md +43 -0
  2. package/VERSION-PIN.md +27 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/manifest-next-ingress.d.ts +213 -0
  5. package/dist/manifest-next-ingress.js +187 -0
  6. package/dist/manifest-next-reach.d.ts +40 -0
  7. package/dist/manifest-next-reach.js +48 -0
  8. package/dist/manifest-next.d.ts +133 -8
  9. package/dist/manifest-next.js +7 -46
  10. package/dist/manifest-static.d.ts +6 -0
  11. package/dist/manifest-static.js +10 -0
  12. package/dist/manifest.d.ts +67 -0
  13. package/dist/manifest.js +7 -0
  14. package/dist/offline/connector.d.ts +2 -0
  15. package/dist/offline/connector.js +6 -2
  16. package/dist/offline/management-types.d.ts +25 -0
  17. package/dist/offline/management-types.js +1 -0
  18. package/dist/runtime-contracts.js +1 -1
  19. package/dist/sdk.d.ts +8 -1
  20. package/dist/server/api-client.d.ts +27 -0
  21. package/dist/server/api-client.js +39 -0
  22. package/dist/server/broker-contract.d.ts +33 -6
  23. package/dist/server/broker-contract.js +20 -2
  24. package/dist/server/client.d.ts +32 -45
  25. package/dist/server/client.js +72 -101
  26. package/dist/server/connection-retry.d.ts +12 -0
  27. package/dist/server/connection-retry.js +40 -0
  28. package/dist/server/errors.d.ts +37 -2
  29. package/dist/server/errors.js +66 -6
  30. package/dist/server/external-context.d.ts +21 -0
  31. package/dist/server/external-context.js +19 -0
  32. package/dist/server/ingress-control-contract.d.ts +272 -0
  33. package/dist/server/ingress-control-contract.js +196 -0
  34. package/dist/server/ingress-routes.d.ts +76 -0
  35. package/dist/server/ingress-routes.js +150 -0
  36. package/dist/server/internal/signed-token.d.ts +15 -0
  37. package/dist/server/internal/signed-token.js +67 -0
  38. package/dist/server/internal/v1-context.d.ts +18 -0
  39. package/dist/server/internal/v1-context.js +26 -0
  40. package/dist/server/internal/verify-any.d.ts +22 -0
  41. package/dist/server/internal/verify-any.js +61 -0
  42. package/dist/server/logger.d.ts +1 -1
  43. package/dist/server/principal.d.ts +48 -0
  44. package/dist/server/principal.js +39 -0
  45. package/dist/server/processes.d.ts +56 -0
  46. package/dist/server/processes.js +13 -0
  47. package/dist/server/request-context.d.ts +121 -5
  48. package/dist/server/request-context.js +105 -34
  49. package/dist/server/runtime-config.d.ts +1 -1
  50. package/dist/server/testing.d.ts +40 -0
  51. package/dist/server/testing.js +86 -0
  52. package/dist/server.d.ts +9 -4
  53. package/dist/server.js +5 -2
  54. package/dist/templates/nextjs/README.md +9 -0
  55. package/dist/templates/nextjs/package.json +3 -1
  56. package/dist/templates/nextjs/tests/server.test.mjs +25 -0
  57. package/dist/templates/react-vite/package.json +1 -1
  58. package/dist/tunnel/protocol.js +2 -4
  59. package/dist/tunnel/reserved-headers.d.ts +7 -0
  60. package/dist/tunnel/reserved-headers.js +20 -0
  61. package/package.json +19 -3
  62. package/templates/nextjs/README.md +9 -0
  63. package/templates/nextjs/package.json +3 -1
  64. package/templates/nextjs/tests/server.test.mjs +25 -0
  65. package/templates/react-vite/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { artifactNextAuditCapabilitySchema } from './manifest-next-reach.js';
2
3
  /** Approved major/minor profile. Builds additionally record exact patch versions. */
3
4
  export declare const ARTIFACT_NEXT_RUNTIME: Readonly<{
4
5
  sdk: "sequence";
@@ -20,14 +21,8 @@ export declare const ARTIFACT_NEXT_RESOURCE_DEFAULTS: {
20
21
  max_instances: number;
21
22
  timeout_seconds: number;
22
23
  };
23
- /**
24
- * Where the server's audit events (`client.audit.record`) go: an Atlas audit service id. Every
25
- * application may record under `artifact_studio`; Atlas admits a first-party service, such as
26
- * `application_portal`, only for the projects it registers for it. Server-only: browsers can't audit.
27
- */
28
- export declare const artifactNextAuditCapabilitySchema: z.ZodObject<{
29
- service: z.ZodString;
30
- }, z.core.$strict>;
24
+ export { artifactNextAuditCapabilitySchema };
25
+ export * from './manifest-next-ingress.js';
31
26
  export declare const artifactNextServerCapabilitiesSchema: z.ZodPrefault<z.ZodObject<{
32
27
  audit: z.ZodOptional<z.ZodObject<{
33
28
  service: z.ZodString;
@@ -132,6 +127,71 @@ export declare const artifactNextServerSchema: z.ZodPrefault<z.ZodObject<{
132
127
  lattice: z.ZodOptional<z.ZodObject<{
133
128
  accept: z.ZodDefault<z.ZodArray<z.ZodString>>;
134
129
  }, z.core.$strict>>;
130
+ ingress: z.ZodOptional<z.ZodObject<{
131
+ external: z.ZodArray<z.ZodObject<{
132
+ id: z.ZodString;
133
+ provider: z.ZodString;
134
+ service_account: z.ZodString;
135
+ headers: z.ZodDefault<z.ZodArray<z.ZodString>>;
136
+ capabilities: z.ZodPrefault<z.ZodObject<{
137
+ storage: z.ZodOptional<z.ZodRecord<z.ZodUUID, z.ZodEnum<{
138
+ viewer: "viewer";
139
+ editor: "editor";
140
+ admin: "admin";
141
+ }>>>;
142
+ data: z.ZodPrefault<z.ZodObject<{
143
+ read: z.ZodDefault<z.ZodArray<z.ZodString>>;
144
+ write: z.ZodDefault<z.ZodArray<z.ZodString>>;
145
+ }, z.core.$strict>>;
146
+ api: z.ZodPrefault<z.ZodObject<{
147
+ read: z.ZodDefault<z.ZodArray<z.ZodString>>;
148
+ write: z.ZodDefault<z.ZodArray<z.ZodString>>;
149
+ }, z.core.$strict>>;
150
+ functions: z.ZodPrefault<z.ZodObject<{
151
+ invoke: z.ZodDefault<z.ZodArray<z.ZodString>>;
152
+ }, z.core.$strict>>;
153
+ audit: z.ZodOptional<z.ZodObject<{
154
+ service: z.ZodString;
155
+ }, z.core.$strict>>;
156
+ processes: z.ZodOptional<z.ZodNever>;
157
+ }, z.core.$strict>>;
158
+ evidence: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
159
+ bind: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodEnum<{
160
+ email: "email";
161
+ subject: "subject";
162
+ authTime: "authTime";
163
+ amr: "amr";
164
+ "client.ip": "client.ip";
165
+ "client.userAgent": "client.userAgent";
166
+ issuer: "issuer";
167
+ }>>>;
168
+ fresh_auth_seconds: z.ZodOptional<z.ZodNumber>;
169
+ }, z.core.$strict>>>;
170
+ routes: z.ZodArray<z.ZodObject<{
171
+ path: z.ZodString;
172
+ methods: z.ZodArray<z.ZodEnum<{
173
+ GET: "GET";
174
+ POST: "POST";
175
+ PUT: "PUT";
176
+ PATCH: "PATCH";
177
+ DELETE: "DELETE";
178
+ }>>;
179
+ fresh_auth_seconds: z.ZodOptional<z.ZodNumber>;
180
+ max_body_bytes: z.ZodDefault<z.ZodNumber>;
181
+ responses: z.ZodDefault<z.ZodArray<z.ZodEnum<{
182
+ "application/json": "application/json";
183
+ "application/problem+json": "application/problem+json";
184
+ "application/pdf": "application/pdf";
185
+ "application/zip": "application/zip";
186
+ "image/png": "image/png";
187
+ "image/jpeg": "image/jpeg";
188
+ "image/webp": "image/webp";
189
+ "text/csv": "text/csv";
190
+ "application/octet-stream": "application/octet-stream";
191
+ }>>>;
192
+ }, z.core.$strict>>;
193
+ }, z.core.$strict>>;
194
+ }, z.core.$strict>>;
135
195
  }, z.core.$strict>>;
136
196
  export declare const artifactStudioNextManifestSchema: z.ZodObject<{
137
197
  ontology: z.ZodOptional<z.ZodObject<{
@@ -251,6 +311,71 @@ export declare const artifactStudioNextManifestSchema: z.ZodObject<{
251
311
  lattice: z.ZodOptional<z.ZodObject<{
252
312
  accept: z.ZodDefault<z.ZodArray<z.ZodString>>;
253
313
  }, z.core.$strict>>;
314
+ ingress: z.ZodOptional<z.ZodObject<{
315
+ external: z.ZodArray<z.ZodObject<{
316
+ id: z.ZodString;
317
+ provider: z.ZodString;
318
+ service_account: z.ZodString;
319
+ headers: z.ZodDefault<z.ZodArray<z.ZodString>>;
320
+ capabilities: z.ZodPrefault<z.ZodObject<{
321
+ storage: z.ZodOptional<z.ZodRecord<z.ZodUUID, z.ZodEnum<{
322
+ viewer: "viewer";
323
+ editor: "editor";
324
+ admin: "admin";
325
+ }>>>;
326
+ data: z.ZodPrefault<z.ZodObject<{
327
+ read: z.ZodDefault<z.ZodArray<z.ZodString>>;
328
+ write: z.ZodDefault<z.ZodArray<z.ZodString>>;
329
+ }, z.core.$strict>>;
330
+ api: z.ZodPrefault<z.ZodObject<{
331
+ read: z.ZodDefault<z.ZodArray<z.ZodString>>;
332
+ write: z.ZodDefault<z.ZodArray<z.ZodString>>;
333
+ }, z.core.$strict>>;
334
+ functions: z.ZodPrefault<z.ZodObject<{
335
+ invoke: z.ZodDefault<z.ZodArray<z.ZodString>>;
336
+ }, z.core.$strict>>;
337
+ audit: z.ZodOptional<z.ZodObject<{
338
+ service: z.ZodString;
339
+ }, z.core.$strict>>;
340
+ processes: z.ZodOptional<z.ZodNever>;
341
+ }, z.core.$strict>>;
342
+ evidence: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
343
+ bind: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodEnum<{
344
+ email: "email";
345
+ subject: "subject";
346
+ authTime: "authTime";
347
+ amr: "amr";
348
+ "client.ip": "client.ip";
349
+ "client.userAgent": "client.userAgent";
350
+ issuer: "issuer";
351
+ }>>>;
352
+ fresh_auth_seconds: z.ZodOptional<z.ZodNumber>;
353
+ }, z.core.$strict>>>;
354
+ routes: z.ZodArray<z.ZodObject<{
355
+ path: z.ZodString;
356
+ methods: z.ZodArray<z.ZodEnum<{
357
+ GET: "GET";
358
+ POST: "POST";
359
+ PUT: "PUT";
360
+ PATCH: "PATCH";
361
+ DELETE: "DELETE";
362
+ }>>;
363
+ fresh_auth_seconds: z.ZodOptional<z.ZodNumber>;
364
+ max_body_bytes: z.ZodDefault<z.ZodNumber>;
365
+ responses: z.ZodDefault<z.ZodArray<z.ZodEnum<{
366
+ "application/json": "application/json";
367
+ "application/problem+json": "application/problem+json";
368
+ "application/pdf": "application/pdf";
369
+ "application/zip": "application/zip";
370
+ "image/png": "image/png";
371
+ "image/jpeg": "image/jpeg";
372
+ "image/webp": "image/webp";
373
+ "text/csv": "text/csv";
374
+ "application/octet-stream": "application/octet-stream";
375
+ }>>>;
376
+ }, z.core.$strict>>;
377
+ }, z.core.$strict>>;
378
+ }, z.core.$strict>>;
254
379
  }, z.core.$strict>>;
255
380
  targets: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
256
381
  url: z.ZodString;
@@ -1,8 +1,9 @@
1
- import { storageScopesSchema } from '@sequenceholdings/storage';
2
1
  import { ontologyContractSchema } from '@sequenceholdings/orm/canonical';
3
2
  import { z } from 'zod';
4
3
  import { capabilityPinsSchema, customRolesBlockSchema, validateCapabilityPins } from './manifest-custom-roles.js';
5
4
  import { isManagedServerInvokePath } from './server/managed-server-path.js';
5
+ import { artifactNextIngressSchema, validateIngressAgainstServer } from './manifest-next-ingress.js';
6
+ import { artifactNextAuditCapabilitySchema, reachShape, serviceAccountRef } from './manifest-next-reach.js';
6
7
  import { apiCapabilityPathAllowed, artifactPresentationSchema, artifactStudioStaticManifestSchema, sidebarBadgeSchema, } from './manifest-static.js';
7
8
  /** Approved major/minor profile. Builds additionally record exact patch versions. */
8
9
  export const ARTIFACT_NEXT_RUNTIME = Object.freeze({ sdk: 'sequence', node: 24, react: 19, next: '16.3' });
@@ -11,51 +12,8 @@ export const ARTIFACT_NEXT_APPROVED_PACKAGES = Object.freeze({ next: '16.3.4', r
11
12
  export const ARTIFACT_NEXT_RESOURCE_DEFAULTS = {
12
13
  cpu: 1, memory_mb: 1024, concurrency: 20, min_instances: 0, max_instances: 3, timeout_seconds: 60,
13
14
  };
14
- const boundedRef = z.string().min(1).max(255).regex(/^[a-zA-Z0-9][a-zA-Z0-9_./:-]*$/).refine((value) => value.split('/').every((part) => part !== '' && part !== '.' && part !== '..'), 'Resource references cannot contain empty segments or traversal');
15
- const serviceAccountRef = z.string().regex(/^([a-z][a-z0-9-]{1,98}|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/);
16
- const apiPath = z.string().min(1).max(512).refine((value) => {
17
- if (!value.startsWith('/api/') || value === '/api/' || value === '/api/*')
18
- return false;
19
- if (/[\\%?#\s\x00-\x1f]/.test(value))
20
- return false;
21
- return value.split('/').slice(1).every((part, index, parts) => part !== '.' && part !== '..' && (part !== '' || index === parts.length - 1));
22
- }, 'API capability paths must be scoped below /api/ without encoded paths, traversal, queries, or fragments');
23
- // ORM references are what a delegated data token covers (orm-data-plane checkDataTokenScope):
24
- // a query needs namespace/table for every table it reads, and a mutation needs its
25
- // namespace/ops/Operation (or table coverage). Any other shape can never match, so it is
26
- // a typo to report here rather than a 403 at request time. The patterns mirror the ORM's
27
- // NAMESPACE_PATTERN, IDENTIFIER_PATTERN and GraphQL operation names; they are kept local so
28
- // browser code that parses manifests does not load the ORM package. platformUsers is the
29
- // ORM's built-in platform-user entity (PLATFORM_USER_TABLE), a logical key outside the
30
- // identifier pattern that queries traversing user relations read.
31
- const ormTableRef = /^[a-z][a-z0-9_]{0,40}\/(?:[a-z][a-z0-9_]{0,62}|platformUsers)$/;
32
- const ormOperationRef = /^[a-z][a-z0-9_]{0,40}\/ops\/[_A-Za-z][_0-9A-Za-z]*$/;
33
- const dataReadRef = boundedRef.refine((ref) => ormTableRef.test(ref), 'ORM read references use namespace/table');
34
- const dataWriteRef = boundedRef.refine((ref) => ormTableRef.test(ref) || ormOperationRef.test(ref), 'ORM write references use namespace/ops/Operation or namespace/table');
35
- const latticeProcessRef = z.string().min(2).max(128).regex(/^[A-Za-z0-9._-]+$/, 'Process references are Lattice process ids');
36
- const reachShape = {
37
- storage: storageScopesSchema.optional(),
38
- data: z.strictObject({ read: z.array(dataReadRef).max(256).default([]), write: z.array(dataWriteRef).max(256).default([]) }).prefault({}),
39
- api: z.strictObject({ read: z.array(apiPath).max(256).default([]), write: z.array(apiPath).max(256).default([]) }).prefault({}),
40
- functions: z.strictObject({ invoke: z.array(boundedRef).max(256).default([]) }).prefault({}),
41
- // `start`: processes the server may start runs of. `read`: processes whose runs, template and
42
- // the user's own steps it may read. `act`: processes whose human steps it may advance and
43
- // reassign, and whose runs' viewers it may manage. All name exact process ids; the user's own
44
- // Invoker / Viewer / Advancer / Owner grants decide what happens.
45
- processes: z.strictObject({
46
- start: z.array(latticeProcessRef).max(256).default([]),
47
- read: z.array(latticeProcessRef).max(256).default([]),
48
- act: z.array(latticeProcessRef).max(256).default([]),
49
- }).prefault({}),
50
- };
51
- /**
52
- * Where the server's audit events (`client.audit.record`) go: an Atlas audit service id. Every
53
- * application may record under `artifact_studio`; Atlas admits a first-party service, such as
54
- * `application_portal`, only for the projects it registers for it. Server-only: browsers can't audit.
55
- */
56
- export const artifactNextAuditCapabilitySchema = z.strictObject({
57
- service: z.string().regex(/^[a-z][a-z0-9_]{0,63}$/, 'Audit services are Atlas audit service ids, such as artifact_studio'),
58
- });
15
+ export { artifactNextAuditCapabilitySchema };
16
+ export * from './manifest-next-ingress.js';
59
17
  export const artifactNextServerCapabilitiesSchema = z.strictObject({
60
18
  ...reachShape,
61
19
  audit: artifactNextAuditCapabilitySchema.optional(),
@@ -118,6 +76,8 @@ export const artifactNextServerSchema = z.strictObject({
118
76
  lattice: z.strictObject({
119
77
  accept: z.array(managedServerInvokePath).max(32).default([]),
120
78
  }).optional(),
79
+ /** Front doors for callers that are not Atlas users. Omitted means none: external callers are refused. */
80
+ ingress: artifactNextIngressSchema.optional(),
121
81
  }).superRefine((server, ctx) => {
122
82
  if (new Set(server.secrets.map((secret) => secret.name)).size !== server.secrets.length) {
123
83
  ctx.addIssue({ code: 'custom', path: ['secrets'], message: 'Each secret environment name must be unique' });
@@ -128,6 +88,7 @@ export const artifactNextServerSchema = z.strictObject({
128
88
  if (server.lattice && new Set(server.lattice.accept).size !== server.lattice.accept.length) {
129
89
  ctx.addIssue({ code: 'custom', path: ['lattice', 'accept'], message: 'Lattice accept paths must be unique' });
130
90
  }
91
+ validateIngressAgainstServer({ server, ctx });
131
92
  }).prefault({});
132
93
  const appRoot = z.string().min(1).max(512).refine((value) => {
133
94
  if (value === '.')
@@ -23,6 +23,12 @@ export declare const artifactOfflineCapabilitySchema: z.ZodObject<{
23
23
  policy_version: z.ZodNumber;
24
24
  }, z.core.$strip>;
25
25
  export type ArtifactOfflineCapability = z.infer<typeof artifactOfflineCapabilitySchema>;
26
+ /**
27
+ * Whether {@link apiCapabilityPathAllowed} treats an entry as a prefix: a trailing `/`, or a
28
+ * trailing `/*` with no other whole-segment `*`. Such an entry admits every path below it,
29
+ * including routes added later. An entry with a mid-path `*` matches whole segments by count.
30
+ */
31
+ export declare function isPrefixApiCapabilityEntry(entry: string): boolean;
26
32
  export declare function apiCapabilityPathAllowed(pathname: string, allowed: readonly string[]): boolean;
27
33
  export declare const artifactStudioStaticManifestSchema: z.ZodObject<{
28
34
  ontology: z.ZodOptional<z.ZodObject<{
@@ -46,6 +46,16 @@ function hasMidPathWildcard(entry) {
46
46
  const parts = entry.split('/');
47
47
  return parts.slice(1, -1).some((part) => part === '*');
48
48
  }
49
+ /**
50
+ * Whether {@link apiCapabilityPathAllowed} treats an entry as a prefix: a trailing `/`, or a
51
+ * trailing `/*` with no other whole-segment `*`. Such an entry admits every path below it,
52
+ * including routes added later. An entry with a mid-path `*` matches whole segments by count.
53
+ */
54
+ export function isPrefixApiCapabilityEntry(entry) {
55
+ if (entry.includes('*') && (!entry.endsWith('/*') || hasMidPathWildcard(entry)))
56
+ return false;
57
+ return entry.endsWith('/*') || entry.endsWith('/');
58
+ }
49
59
  export function apiCapabilityPathAllowed(pathname, allowed) {
50
60
  return allowed.some((entry) => matchesApiCapabilityEntry(pathname, entry));
51
61
  }
@@ -204,6 +204,71 @@ export declare const artifactStudioManifestSchema: z.ZodUnion<readonly [z.ZodObj
204
204
  lattice: z.ZodOptional<z.ZodObject<{
205
205
  accept: z.ZodDefault<z.ZodArray<z.ZodString>>;
206
206
  }, z.core.$strict>>;
207
+ ingress: z.ZodOptional<z.ZodObject<{
208
+ external: z.ZodArray<z.ZodObject<{
209
+ id: z.ZodString;
210
+ provider: z.ZodString;
211
+ service_account: z.ZodString;
212
+ headers: z.ZodDefault<z.ZodArray<z.ZodString>>;
213
+ capabilities: z.ZodPrefault<z.ZodObject<{
214
+ storage: z.ZodOptional<z.ZodRecord<z.ZodUUID, z.ZodEnum<{
215
+ viewer: "viewer";
216
+ editor: "editor";
217
+ admin: "admin";
218
+ }>>>;
219
+ data: z.ZodPrefault<z.ZodObject<{
220
+ read: z.ZodDefault<z.ZodArray<z.ZodString>>;
221
+ write: z.ZodDefault<z.ZodArray<z.ZodString>>;
222
+ }, z.core.$strict>>;
223
+ api: z.ZodPrefault<z.ZodObject<{
224
+ read: z.ZodDefault<z.ZodArray<z.ZodString>>;
225
+ write: z.ZodDefault<z.ZodArray<z.ZodString>>;
226
+ }, z.core.$strict>>;
227
+ functions: z.ZodPrefault<z.ZodObject<{
228
+ invoke: z.ZodDefault<z.ZodArray<z.ZodString>>;
229
+ }, z.core.$strict>>;
230
+ audit: z.ZodOptional<z.ZodObject<{
231
+ service: z.ZodString;
232
+ }, z.core.$strict>>;
233
+ processes: z.ZodOptional<z.ZodNever>;
234
+ }, z.core.$strict>>;
235
+ evidence: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
236
+ bind: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodEnum<{
237
+ email: "email";
238
+ subject: "subject";
239
+ authTime: "authTime";
240
+ amr: "amr";
241
+ "client.ip": "client.ip";
242
+ "client.userAgent": "client.userAgent";
243
+ issuer: "issuer";
244
+ }>>>;
245
+ fresh_auth_seconds: z.ZodOptional<z.ZodNumber>;
246
+ }, z.core.$strict>>>;
247
+ routes: z.ZodArray<z.ZodObject<{
248
+ path: z.ZodString;
249
+ methods: z.ZodArray<z.ZodEnum<{
250
+ GET: "GET";
251
+ POST: "POST";
252
+ PUT: "PUT";
253
+ PATCH: "PATCH";
254
+ DELETE: "DELETE";
255
+ }>>;
256
+ fresh_auth_seconds: z.ZodOptional<z.ZodNumber>;
257
+ max_body_bytes: z.ZodDefault<z.ZodNumber>;
258
+ responses: z.ZodDefault<z.ZodArray<z.ZodEnum<{
259
+ "application/json": "application/json";
260
+ "application/problem+json": "application/problem+json";
261
+ "application/pdf": "application/pdf";
262
+ "application/zip": "application/zip";
263
+ "image/png": "image/png";
264
+ "image/jpeg": "image/jpeg";
265
+ "image/webp": "image/webp";
266
+ "text/csv": "text/csv";
267
+ "application/octet-stream": "application/octet-stream";
268
+ }>>>;
269
+ }, z.core.$strict>>;
270
+ }, z.core.$strict>>;
271
+ }, z.core.$strict>>;
207
272
  }, z.core.$strict>>;
208
273
  targets: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
209
274
  url: z.ZodString;
@@ -226,3 +291,5 @@ export type ArtifactStudioManifest = ArtifactStudioStaticManifest | ArtifactStud
226
291
  export type ArtifactStudioManifestInput = z.input<typeof artifactStudioManifestSchema>;
227
292
  export declare function parseArtifactStudioManifest(value: unknown): ArtifactStudioManifest;
228
293
  export declare function isNextArtifactManifest(manifest: ArtifactStudioManifest): manifest is ArtifactStudioNextManifest;
294
+ /** Parses an `artifact.bundle.yml` that must be an Artifact Next manifest (schema_version 2). */
295
+ export declare function parseArtifactNextManifest(value: unknown): ArtifactStudioNextManifest;
package/dist/manifest.js CHANGED
@@ -14,3 +14,10 @@ export function parseArtifactStudioManifest(value) {
14
14
  export function isNextArtifactManifest(manifest) {
15
15
  return manifest.artifact.type === 'nextjs';
16
16
  }
17
+ /** Parses an `artifact.bundle.yml` that must be an Artifact Next manifest (schema_version 2). */
18
+ export function parseArtifactNextManifest(value) {
19
+ const manifest = parseArtifactStudioManifest(value);
20
+ if (!isNextArtifactManifest(manifest))
21
+ throw new Error('Expected an Artifact Next manifest (artifact.type nextjs)');
22
+ return manifest;
23
+ }
@@ -2,9 +2,11 @@ import type { SequenceOfflineRequest, SequenceOfflineRequestConnector } from '..
2
2
  import type { OfflineReplayEngine } from './replay.js';
3
3
  import type { OfflineCache, OfflineMutationPolicy, OfflineReadPolicy } from './types.js';
4
4
  export declare class OfflineDataUnavailableError extends Error {
5
+ readonly path: string;
5
6
  constructor(path: string);
6
7
  }
7
8
  export declare class OfflineWriteBlockedError extends Error {
9
+ readonly path: string;
8
10
  constructor(path: string);
9
11
  }
10
12
  export interface ArtifactOfflineConnector {
@@ -1,13 +1,17 @@
1
1
  export class OfflineDataUnavailableError extends Error {
2
+ path;
2
3
  constructor(path) {
3
- super(`No current offline data is available for ${path}`);
4
+ super('No offline data available');
4
5
  this.name = 'OfflineDataUnavailableError';
6
+ this.path = path;
5
7
  }
6
8
  }
7
9
  export class OfflineWriteBlockedError extends Error {
10
+ path;
8
11
  constructor(path) {
9
- super(`Reconnect to complete this action: ${path}`);
12
+ super('Reconnect to complete this action');
10
13
  this.name = 'OfflineWriteBlockedError';
14
+ this.path = path;
11
15
  }
12
16
  }
13
17
  function canUseCachedFallback(response) {
@@ -0,0 +1,25 @@
1
+ export interface SequenceOfflineManagementStatus {
2
+ supported: boolean;
3
+ enrolled: boolean;
4
+ online: boolean;
5
+ pending: number;
6
+ failed: number;
7
+ syncing: boolean;
8
+ lastSyncAt: number | null;
9
+ itemCount?: number;
10
+ itemLabel?: string;
11
+ }
12
+ export interface SequenceOfflineManagementIssue {
13
+ id: string;
14
+ label: string;
15
+ message: string;
16
+ }
17
+ export interface SequenceOfflineManagement {
18
+ status(): Promise<SequenceOfflineManagementStatus>;
19
+ setEnrolled(enrolled: boolean): Promise<void>;
20
+ sync(): Promise<void>;
21
+ issues(): Promise<SequenceOfflineManagementIssue[]>;
22
+ retry(id: string): Promise<void>;
23
+ discard(id: string): Promise<void>;
24
+ subscribe(listener: () => void): () => void;
25
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -20,7 +20,7 @@ const imageReferenceSchema = z.string().max(1024).regex(/^[a-z0-9]+(?:[.-][a-z0-
20
20
  const excludedSourceSegments = new Set([
21
21
  '.git', 'node_modules', '.next', '.npmrc', '.netrc', '.aws', '.ssh', '.config',
22
22
  'dist', '.artifact-studio', '.git-credentials', '.pypirc', '.azure', '.gcloud', '.doppler',
23
- '.turbo', 'coverage', '.docker',
23
+ '.turbo', 'coverage', '.docker', '.seq-next-output.json',
24
24
  ]);
25
25
  /** Shared upload exclusion policy. Content scanning and filesystem containment remain separate checks. */
26
26
  export function isExcludedArtifactSourcePath({ path }) {
package/dist/sdk.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { SequenceOfflineManagement } from './offline/management-types.js';
2
+ export type { SequenceOfflineManagement, SequenceOfflineManagementStatus, SequenceOfflineManagementIssue } from './offline/management-types.js';
1
3
  import { type StartStorageUpload, type StorageUploadSession } from '@sequenceholdings/storage';
2
4
  export { createArtifactOrmExecutor, type ArtifactOrmExecutorConfig } from './sdk-orm.js';
3
5
  export type { ArtifactOrmJsonScalars } from './orm-json-scalars.js';
@@ -78,6 +80,9 @@ export interface SequenceOfflineRequestConnector {
78
80
  }): void | (() => void);
79
81
  }
80
82
  export interface SequenceOffline {
83
+ registerManagement(adapter: SequenceOfflineManagement): () => void;
84
+ openSettings(): Promise<void>;
85
+ isManagementSession(): boolean;
81
86
  /**
82
87
  * Install the artifact's request policy beneath seq.api. Returns a disposer
83
88
  * that restores the network-only default when it still owns registration.
@@ -395,7 +400,9 @@ export declare function createArtifactStorageClient(sdk?: SequenceArtifactSdk):
395
400
  size: number | null;
396
401
  contentType: string | null;
397
402
  }>;
398
- createFolder: (name: string, parentId?: string | null, { idempotencyKey, }?: {
403
+ createFolder: (name: string, parentId
404
+ /** The specific step run (the assignee's task) — the step-scoped id reviewers hold access to. */
405
+ ? /** The specific step run (the assignee's task) — the step-scoped id reviewers hold access to. */: string | null, { idempotencyKey, }?: {
399
406
  idempotencyKey?: string;
400
407
  }) => Promise<{
401
408
  id: string;
@@ -0,0 +1,27 @@
1
+ import type { SequenceApiFetchResponse } from '../sdk.js';
2
+ import { type ArtifactServerMode, type ArtifactServerRequest } from './broker-contract.js';
3
+ export interface ArtifactServerFetchOptions {
4
+ method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
5
+ body?: unknown;
6
+ signal?: AbortSignal;
7
+ }
8
+ /** Sends one broker operation; the client's transport (retries, the external-principal gate). */
9
+ export type ArtifactBrokerRequest = (operation: ArtifactServerRequest, options?: {
10
+ signal?: AbortSignal;
11
+ stream?: boolean;
12
+ }) => Promise<Response>;
13
+ /** `client.api`: Atlas routes reached through the broker as `api` operations. */
14
+ export declare function createApiClient({ mode, request, json }: {
15
+ mode: ArtifactServerMode;
16
+ request: ArtifactBrokerRequest;
17
+ json: (operation: ArtifactServerRequest, signal?: AbortSignal) => Promise<unknown>;
18
+ }): {
19
+ request: (path: string, options?: ArtifactServerFetchOptions) => Promise<Response>;
20
+ fetch<TBody = unknown>(path: string, options?: ArtifactServerFetchOptions): Promise<SequenceApiFetchResponse<TBody>>;
21
+ stream(path: string, options?: ArtifactServerFetchOptions): Promise<ReadableStream<Uint8Array<ArrayBuffer>>>;
22
+ get: <T = unknown>(path: string) => Promise<T>;
23
+ post: <T = unknown>(path: string, body?: unknown) => Promise<T>;
24
+ put: <T = unknown>(path: string, body?: unknown) => Promise<T>;
25
+ patch: <T = unknown>(path: string, body?: unknown) => Promise<T>;
26
+ delete: <T = unknown>(path: string, body?: unknown) => Promise<T>;
27
+ };
@@ -0,0 +1,39 @@
1
+ import { artifactServerRequestSchema } from './broker-contract.js';
2
+ import { ArtifactServerError, stepUpErrorFromResponse } from './errors.js';
3
+ const responseHeaders = ['content-type', 'content-disposition', 'content-length', 'retry-after'];
4
+ /** `client.api`: Atlas routes reached through the broker as `api` operations. */
5
+ export function createApiClient({ mode, request, json }) {
6
+ const operation = (path, options = {}) => artifactServerRequestSchema.parse({ operation: 'api', mode, method: options.method ?? 'GET', path, body: options.body });
7
+ const fetchResponse = (path, options = {}) => request(operation(path, options), { signal: options.signal });
8
+ const typedJson = async (path, options = {}) => {
9
+ // Explicit caller result types match the existing browser SDK; the server validates endpoint schemas.
10
+ return await json(operation(path, options), options.signal);
11
+ };
12
+ return {
13
+ request: fetchResponse,
14
+ async fetch(path, options = {}) {
15
+ const response = await fetchResponse(path, options);
16
+ const contentType = response.headers.get('content-type') ?? '';
17
+ const body = response.status === 204 ? undefined : contentType.includes('json') ? await response.json() : await response.arrayBuffer();
18
+ // The caller declares the endpoint's response type, consistent with SequenceApiFetchResponse.
19
+ return { ok: response.ok, status: response.status, body: body, headers: Object.fromEntries(responseHeaders.flatMap(key => {
20
+ const value = response.headers.get(key);
21
+ return value === null ? [] : [[key, value]];
22
+ })) };
23
+ },
24
+ async stream(path, options = {}) {
25
+ // A stream outlives the broker's answer deadline: only its headers must arrive in time.
26
+ const response = await request(operation(path, options), { signal: options.signal, stream: true });
27
+ if (!response.ok || !response.body) {
28
+ throw await stepUpErrorFromResponse(response) ??
29
+ new ArtifactServerError(response.status, 'stream_unavailable', 'Atlas did not return a readable response');
30
+ }
31
+ return response.body;
32
+ },
33
+ get: (path) => typedJson(path),
34
+ post: (path, body) => typedJson(path, { method: 'POST', body }),
35
+ put: (path, body) => typedJson(path, { method: 'PUT', body }),
36
+ patch: (path, body) => typedJson(path, { method: 'PATCH', body }),
37
+ delete: (path, body) => typedJson(path, { method: 'DELETE', body }),
38
+ };
39
+ }
@@ -3,10 +3,10 @@ export { ORM_JSON_SCALARS_HEADER, ORM_LOSSLESS_JSON_SCALARS, type ArtifactOrmJso
3
3
  export declare const artifactServerMethodSchema: z.ZodEnum<{
4
4
  GET: "GET";
5
5
  POST: "POST";
6
- DELETE: "DELETE";
7
- HEAD: "HEAD";
8
6
  PUT: "PUT";
9
7
  PATCH: "PATCH";
8
+ DELETE: "DELETE";
9
+ HEAD: "HEAD";
10
10
  }>;
11
11
  export declare const artifactServerModeSchema: z.ZodDefault<z.ZodEnum<{
12
12
  service: "service";
@@ -18,6 +18,8 @@ export declare function isArtifactApiPath(path: string): boolean;
18
18
  export declare const ARTIFACT_PROCESS_RUN_STATUSES: readonly ["pending", "running", "completed", "failed", "cancelled", "timed_out"];
19
19
  /** Lattice lists at most this many runs per call. */
20
20
  export declare const ARTIFACT_PROCESS_RUNS_LIMIT = 500;
21
+ /** A run-events read returns at most this many events per call, as the run's stream drains them. */
22
+ export declare const ARTIFACT_PROCESS_RUN_EVENTS_LIMIT = 1000;
21
23
  /** Which of the user's human steps to list: parked and waiting on them, or already done. */
22
24
  export declare const ARTIFACT_PROCESS_TASK_VIEWS: readonly ["active", "completed"];
23
25
  /** Lattice lists at most this many human steps per call, as its own inbox does. */
@@ -45,10 +47,10 @@ export declare const artifactServerRequestSchema: z.ZodDiscriminatedUnion<[z.Zod
45
47
  method: z.ZodEnum<{
46
48
  GET: "GET";
47
49
  POST: "POST";
48
- DELETE: "DELETE";
49
- HEAD: "HEAD";
50
50
  PUT: "PUT";
51
51
  PATCH: "PATCH";
52
+ DELETE: "DELETE";
53
+ HEAD: "HEAD";
52
54
  }>;
53
55
  path: z.ZodString;
54
56
  body: z.ZodOptional<z.ZodUnknown>;
@@ -71,10 +73,10 @@ export declare const artifactServerRequestSchema: z.ZodDiscriminatedUnion<[z.Zod
71
73
  method: z.ZodEnum<{
72
74
  GET: "GET";
73
75
  POST: "POST";
74
- DELETE: "DELETE";
75
- HEAD: "HEAD";
76
76
  PUT: "PUT";
77
77
  PATCH: "PATCH";
78
+ DELETE: "DELETE";
79
+ HEAD: "HEAD";
78
80
  }>;
79
81
  path: z.ZodString;
80
82
  body: z.ZodOptional<z.ZodUnknown>;
@@ -94,6 +96,7 @@ export declare const artifactServerRequestSchema: z.ZodDiscriminatedUnion<[z.Zod
94
96
  }>>;
95
97
  process: z.ZodString;
96
98
  runId: z.ZodOptional<z.ZodString>;
99
+ startNodeId: z.ZodOptional<z.ZodString>;
97
100
  title: z.ZodOptional<z.ZodString>;
98
101
  entity: z.ZodOptional<z.ZodObject<{
99
102
  type: z.ZodString;
@@ -132,6 +135,15 @@ export declare const artifactServerRequestSchema: z.ZodDiscriminatedUnion<[z.Zod
132
135
  user: "user";
133
136
  }>>;
134
137
  runId: z.ZodString;
138
+ }, z.core.$strict>, z.ZodObject<{
139
+ operation: z.ZodLiteral<"lattice_run_events">;
140
+ mode: z.ZodDefault<z.ZodEnum<{
141
+ service: "service";
142
+ user: "user";
143
+ }>>;
144
+ runId: z.ZodString;
145
+ since: z.ZodOptional<z.ZodString>;
146
+ limit: z.ZodOptional<z.ZodNumber>;
135
147
  }, z.core.$strict>, z.ZodObject<{
136
148
  operation: z.ZodLiteral<"lattice_process">;
137
149
  mode: z.ZodDefault<z.ZodEnum<{
@@ -172,6 +184,21 @@ export declare const artifactServerRequestSchema: z.ZodDiscriminatedUnion<[z.Zod
172
184
  }>>;
173
185
  runId: z.ZodString;
174
186
  stepId: z.ZodString;
187
+ }, z.core.$strict>, z.ZodObject<{
188
+ operation: z.ZodLiteral<"lattice_cancel">;
189
+ mode: z.ZodDefault<z.ZodEnum<{
190
+ service: "service";
191
+ user: "user";
192
+ }>>;
193
+ runId: z.ZodString;
194
+ }, z.core.$strict>, z.ZodObject<{
195
+ operation: z.ZodLiteral<"lattice_reset_step">;
196
+ mode: z.ZodDefault<z.ZodEnum<{
197
+ service: "service";
198
+ user: "user";
199
+ }>>;
200
+ runId: z.ZodString;
201
+ stepId: z.ZodString;
175
202
  }, z.core.$strict>, z.ZodObject<{
176
203
  operation: z.ZodLiteral<"lattice_viewers">;
177
204
  mode: z.ZodDefault<z.ZodEnum<{