@sequenceholdings/managed-functions 0.3.4 → 0.4.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.
package/README.md CHANGED
@@ -13,6 +13,29 @@ function consumer or branch on a function ID.
13
13
 
14
14
  ## ORM as the invoking user
15
15
 
16
+ ### Default SQL (planned SDK 0.4.0)
17
+
18
+ With the matching Atlas runtime, use the same caller-scoped executor without
19
+ an operation manifest:
20
+
21
+ ```ts
22
+ const orm = createFunctionOrmExecutor({ request, baseUrl: platformOrigin, namespace: 'lending' })
23
+ const result = await orm.sql({
24
+ sql: `SELECT l.id, c.name FROM lending.loans l
25
+ JOIN party.customers c ON c.id = l."customerId"`,
26
+ })
27
+ ```
28
+
29
+ The invocation still needs its existing declared data bindings covering every
30
+ read object, including policy dependencies. SQL does not grant extra access.
31
+ Namespace access, row policies, foreign exports and optional consumer contracts
32
+ remain enforced. Results contain `columns`, array-valued `rows`, and `truncated`;
33
+ numeric/bigint SQL results are always exact strings. Read-only SELECT queries
34
+ are bounded to 1,000 rows / 8 MiB. Source versions are not proof of publication
35
+ or server rollout; the registered-operation workflow below remains supported.
36
+
37
+ ### Registered operations
38
+
16
39
  Available in SDK **0.2.0 and later**. Install the SDK in the function package;
17
40
  the separate ORM authoring/compiler package is not needed in the deployed
18
41
  function. Copy the namespace's generated `operations.manifest.json` into that
@@ -138,6 +161,69 @@ A denied write is still denied; the helper supplies no permission
138
161
  fallback. A network error may follow a successful write: use application-level
139
162
  idempotency and inspect persisted results before retrying.
140
163
 
164
+ ## Read process run status as the service account
165
+
166
+ The process-read client requires SDK **0.3.5**, CLI **0.4.6**, and an environment
167
+ advertising `processes_read` support. These release requirements are not proof
168
+ that a particular environment has been upgraded. Deployment preflight checks
169
+ the environment before uploading.
170
+
171
+ Declare the exact processes and the account that will read them:
172
+
173
+ ```yaml
174
+ service_account: document-runtime
175
+ capabilities:
176
+ processes:
177
+ read: [document-review, document-review-part]
178
+ ```
179
+
180
+ The declaration permits at most 64 distinct process IDs, with at most 8192
181
+ bytes across their names. It grants no process permissions. The attached
182
+ account needs process Viewer access, including visibility of every run for
183
+ paged reads. Process Invoker normally implies Viewer. Processes whose runs
184
+ have narrower visibility are refused instead of returning an incomplete
185
+ activity list that could be mistaken for proof that no run exists.
186
+
187
+ ```ts
188
+ import { createFunctionServiceProcessesClient } from '@sequenceholdings/managed-functions'
189
+
190
+ // Construct inside the handler, using its platform-delivered request and a
191
+ // deployment-configured origin. Never choose the origin from user input.
192
+ const processes = createFunctionServiceProcessesClient({
193
+ request,
194
+ baseUrl: 'https://your-environment.example.com',
195
+ })
196
+ const run = await processes.getRun({ process: 'document-review', runId })
197
+ const page = await processes.listRunsPage({
198
+ process: 'document-review',
199
+ statuses: ['pending', 'running'],
200
+ entity: { type: 'document', ids: documentIds },
201
+ limit: 100,
202
+ })
203
+ ```
204
+
205
+ `getRun` returns only `id`, `processId`, `status`, `entityType`, `entityId`,
206
+ `startedAt` and `completedAt`. Dates are ISO strings; entity fields and
207
+ `completedAt` may be null. Runtime error text, metadata, state, output and steps
208
+ are not exposed. `listRunsPage` returns `{ runs, nextCursor }`; follow every
209
+ non-null cursor with the same filters. Each page permits at most 500 runs and
210
+ 500 entity IDs. `entity.id` and `entity.ids` are mutually exclusive.
211
+ `archived: true` selects archived runs instead of the default unarchived runs.
212
+
213
+ The client sends only an invocation-bound process credential and never follows
214
+ redirects or retries. Atlas rechecks the function version, organization,
215
+ declarations, current service-account attachment and permissions. Completed
216
+ invocation records revoke access; bounded expiry covers delayed ledger writes.
217
+ Create a new client for each invocation and never log or persist its headers.
218
+ Local handler execution without platform delegation cannot use this client.
219
+
220
+ `FunctionProcessReadError` exposes `status` and `code`. Only
221
+ `404 / run_not_found` proves the expected run is absent after authorization.
222
+ Denied, expired, unavailable or malformed reads must not be treated as an
223
+ empty activity list. Reads do not atomically reserve work: applications must
224
+ still coordinate concurrent starts through a durable claim or idempotency
225
+ mechanism.
226
+
141
227
  ## Opt-in cache
142
228
 
143
229
  Opt-in caching inside a Managed Function. When the manifest declares a `cache` block, the platform passes a process-reused `context` as the HTTP handler's third argument. Existing two-argument handlers keep working.
@@ -13,6 +13,13 @@ export declare const MANAGED_FUNCTION_CAPABILITIES: {
13
13
  };
14
14
  };
15
15
  readonly features: {
16
+ readonly processes_read: {
17
+ readonly field: "capabilities.processes.read";
18
+ readonly supported: true;
19
+ readonly limit: "1 to 64 distinct process ids; getRun and listRunsPage only";
20
+ readonly min_cli: "0.4.6";
21
+ readonly min_sdk: "0.3.5";
22
+ };
16
23
  readonly postgres_egress: {
17
24
  readonly field: "egress";
18
25
  readonly supported: true;
@@ -50,6 +57,13 @@ export interface CapabilityTooling {
50
57
  export interface ManagedFunctionCapabilities {
51
58
  tooling: CapabilityTooling;
52
59
  features: {
60
+ processes_read?: {
61
+ field: string;
62
+ supported: boolean;
63
+ limit: string;
64
+ min_cli: string;
65
+ min_sdk: string;
66
+ };
53
67
  postgres_egress?: {
54
68
  field: string;
55
69
  supported: boolean;
@@ -93,6 +107,7 @@ export interface PreflightManifest {
93
107
  capabilities?: {
94
108
  data?: Readonly<Record<string, unknown>>;
95
109
  storage?: unknown;
110
+ processes?: unknown;
96
111
  };
97
112
  }
98
113
  export interface PreflightIssue {
@@ -15,6 +15,13 @@ exports.MANAGED_FUNCTION_CAPABILITIES = {
15
15
  sdk: { package: exports.MANAGED_FUNCTION_SDK_PACKAGE, min: '0.3.0' },
16
16
  },
17
17
  features: {
18
+ processes_read: {
19
+ field: 'capabilities.processes.read',
20
+ supported: true,
21
+ limit: '1 to 64 distinct process ids; getRun and listRunsPage only',
22
+ min_cli: '0.4.6',
23
+ min_sdk: '0.3.5',
24
+ },
18
25
  postgres_egress: {
19
26
  field: 'egress',
20
27
  supported: true,
@@ -58,7 +65,8 @@ function versionIsOlder(installed, required) {
58
65
  return false;
59
66
  }
60
67
  function sdkVersionLowerBound(spec) {
61
- return (0, sdk_range_1.concreteOrStaleSdkSpec)(spec, exports.MANAGED_FUNCTION_CAPABILITIES.features.invoke_timeout.min_sdk);
68
+ const minimum = Object.values(exports.MANAGED_FUNCTION_CAPABILITIES.features).reduce((current, feature) => versionIsOlder(current, feature.min_sdk) ? feature.min_sdk : current, exports.MANAGED_FUNCTION_CAPABILITIES.tooling.sdk.min);
69
+ return (0, sdk_range_1.concreteOrStaleSdkSpec)(spec, minimum);
62
70
  }
63
71
  function sdkVersionFromPackageJson(raw) {
64
72
  let parsed;
package/dist/config.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { FUNCTION_PROCESS_TOKEN_HEADER, FUNCTION_PROCESS_READ_PATH, functionProcessReadScopesSchema, readFunctionProcessScopes, functionProcessReadRequestSchema, functionProcessRunSummarySchema } from './processes-contract';
1
2
  export { shouldReportAtlasHttp } from './http-tracing';
2
3
  import { z } from 'zod';
3
4
  export { MANAGED_FUNCTION_LIMITS, MF_LIMITS_CAPS, MF_LIMITS_DEFAULTS, managedFunctionWorkloadLimitsSchema } from './limits';
package/dist/config.js CHANGED
@@ -1,7 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.cacheManifestSchema = exports.CACHE_MAX_TTL_SECONDS = exports.preflightManagedFunction = exports.parseDeployedPolicy = exports.versionIsOlder = exports.sdkVersionLowerBound = exports.sdkVersionFromPackageJson = exports.isPostgresEgress = exports.formatValidationDetail = exports.MANAGED_FUNCTION_SDK_PACKAGE = exports.MANAGED_FUNCTION_CLI_PACKAGE = exports.MANAGED_FUNCTION_CAPABILITIES = exports.managedFunctionWorkloadLimitsSchema = exports.MF_LIMITS_DEFAULTS = exports.MF_LIMITS_CAPS = exports.MANAGED_FUNCTION_LIMITS = exports.shouldReportAtlasHttp = void 0;
3
+ exports.cacheManifestSchema = exports.CACHE_MAX_TTL_SECONDS = exports.preflightManagedFunction = exports.parseDeployedPolicy = exports.versionIsOlder = exports.sdkVersionLowerBound = exports.sdkVersionFromPackageJson = exports.isPostgresEgress = exports.formatValidationDetail = exports.MANAGED_FUNCTION_SDK_PACKAGE = exports.MANAGED_FUNCTION_CLI_PACKAGE = exports.MANAGED_FUNCTION_CAPABILITIES = exports.managedFunctionWorkloadLimitsSchema = exports.MF_LIMITS_DEFAULTS = exports.MF_LIMITS_CAPS = exports.MANAGED_FUNCTION_LIMITS = exports.shouldReportAtlasHttp = exports.functionProcessRunSummarySchema = exports.functionProcessReadRequestSchema = exports.readFunctionProcessScopes = exports.functionProcessReadScopesSchema = exports.FUNCTION_PROCESS_READ_PATH = exports.FUNCTION_PROCESS_TOKEN_HEADER = void 0;
4
4
  exports.readCacheConfiguration = readCacheConfiguration;
5
+ var processes_contract_1 = require("./processes-contract");
6
+ Object.defineProperty(exports, "FUNCTION_PROCESS_TOKEN_HEADER", { enumerable: true, get: function () { return processes_contract_1.FUNCTION_PROCESS_TOKEN_HEADER; } });
7
+ Object.defineProperty(exports, "FUNCTION_PROCESS_READ_PATH", { enumerable: true, get: function () { return processes_contract_1.FUNCTION_PROCESS_READ_PATH; } });
8
+ Object.defineProperty(exports, "functionProcessReadScopesSchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessReadScopesSchema; } });
9
+ Object.defineProperty(exports, "readFunctionProcessScopes", { enumerable: true, get: function () { return processes_contract_1.readFunctionProcessScopes; } });
10
+ Object.defineProperty(exports, "functionProcessReadRequestSchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessReadRequestSchema; } });
11
+ Object.defineProperty(exports, "functionProcessRunSummarySchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessRunSummarySchema; } });
5
12
  var http_tracing_1 = require("./http-tracing");
6
13
  Object.defineProperty(exports, "shouldReportAtlasHttp", { enumerable: true, get: function () { return http_tracing_1.shouldReportAtlasHttp; } });
7
14
  const zod_1 = require("zod");
@@ -41,9 +41,23 @@ function normalizeCapabilities(value) {
41
41
  postgres_egress: normalizePostgres(features.postgres_egress),
42
42
  http_headers: normalizeHeaders(features.http_headers),
43
43
  invoke_timeout: normalizeTimeout(features.invoke_timeout),
44
+ processes_read: normalizeProcesses(features.processes_read),
44
45
  },
45
46
  };
46
47
  }
48
+ function normalizeProcesses(value) {
49
+ if (!value || typeof value.supported !== 'boolean' || typeof value.limit !== 'string')
50
+ return undefined;
51
+ if (typeof value.min_cli !== 'string' || typeof value.min_sdk !== 'string')
52
+ return undefined;
53
+ return {
54
+ field: typeof value.field === 'string' ? value.field : 'capabilities.processes.read',
55
+ supported: value.supported,
56
+ limit: value.limit,
57
+ min_cli: value.min_cli,
58
+ min_sdk: value.min_sdk,
59
+ };
60
+ }
47
61
  function normalizePostgres(value) {
48
62
  if (!value || typeof value.supported !== 'boolean' || typeof value.limit !== 'string')
49
63
  return undefined;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { createFunctionServiceProcessesClient, FunctionProcessReadError } from './processes';
2
+ export type { FunctionServiceProcessesClient, FunctionServiceProcessesOptions, FunctionProcessRunQuery, FunctionProcessRunSummary, FunctionProcessRunStatus, FunctionProcessRunsPage, FunctionProcessRunsPageQuery, FunctionProcessReadRequest } from './processes';
1
3
  export { installFunctionTracing, runWithFunctionTracing } from './tracing';
2
4
  export { createFunctionStorageClient } from './storage';
3
5
  import { type CacheManager } from "./cache";
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.readCacheConfiguration = exports.cacheManifestSchema = exports.createCacheManager = exports.CacheError = exports.createFunctionStorageClient = exports.runWithFunctionTracing = exports.installFunctionTracing = void 0;
3
+ exports.readCacheConfiguration = exports.cacheManifestSchema = exports.createCacheManager = exports.CacheError = exports.createFunctionStorageClient = exports.runWithFunctionTracing = exports.installFunctionTracing = exports.FunctionProcessReadError = exports.createFunctionServiceProcessesClient = void 0;
4
4
  exports.createManagedFunctionContext = createManagedFunctionContext;
5
+ var processes_1 = require("./processes");
6
+ Object.defineProperty(exports, "createFunctionServiceProcessesClient", { enumerable: true, get: function () { return processes_1.createFunctionServiceProcessesClient; } });
7
+ Object.defineProperty(exports, "FunctionProcessReadError", { enumerable: true, get: function () { return processes_1.FunctionProcessReadError; } });
5
8
  var tracing_1 = require("./tracing");
6
9
  Object.defineProperty(exports, "installFunctionTracing", { enumerable: true, get: function () { return tracing_1.installFunctionTracing; } });
7
10
  Object.defineProperty(exports, "runWithFunctionTracing", { enumerable: true, get: function () { return tracing_1.runWithFunctionTracing; } });
package/dist/orm.d.ts CHANGED
@@ -15,6 +15,29 @@ declare class OrmOperationError extends OrmClientError {
15
15
  readonly name = "OrmOperationError";
16
16
  constructor(message: string, status: number | null, code: string | null, errors?: readonly OperationErrorEntry[]);
17
17
  }
18
+ type SqlQueryParameter = {
19
+ type: 'text' | 'uuid' | 'date' | 'timestamptz' | 'numeric' | 'bigint';
20
+ value: string | null;
21
+ } | {
22
+ type: 'integer' | 'double';
23
+ value: number | null;
24
+ } | {
25
+ type: 'boolean';
26
+ value: boolean | null;
27
+ };
28
+ type SqlQueryVariables = {
29
+ sql: string;
30
+ parameters?: Record<string, SqlQueryParameter>;
31
+ };
32
+ interface SqlQueryResult {
33
+ columns: Array<{
34
+ name: string;
35
+ type: string;
36
+ nullable: boolean;
37
+ }>;
38
+ rows: Array<Array<string | number | boolean | null>>;
39
+ truncated: boolean;
40
+ }
18
41
 
19
42
  /** One entry of `operations.manifest.json` (generated by `orm generate`). */
20
43
  interface ManifestOperation {
@@ -38,6 +61,11 @@ interface OperationExecutor {
38
61
  /** Execute a manifest operation by name (or a raw `sha256:` hash). */
39
62
  execute<TData = Record<string, unknown>>(op: string, variables?: Record<string, unknown>, options?: OperationExecutionOptions): Promise<TData>;
40
63
  }
64
+ /** Additive factory result; existing host wrappers implementing OperationExecutor remain valid. */
65
+ interface SqlOperationExecutor extends OperationExecutor {
66
+ /** Default read-only ontology SQL; no authored operation or manifest needed. */
67
+ sql(variables: SqlQueryVariables): Promise<SqlQueryResult>;
68
+ }
41
69
 
42
70
  type FunctionOrmErrorCode = 'INVALID_CONFIGURATION' | 'MISSING_CALLER_CONTEXT' | 'INVALID_CALLER_CONTEXT' | 'UNSUPPORTED_CALLER' | 'EXPIRED_CALLER_CONTEXT';
43
71
  declare class FunctionOrmError extends Error {
@@ -55,11 +83,11 @@ interface FunctionOrmExecutorOptions {
55
83
  request: FunctionOrmRequest;
56
84
  baseUrl: string;
57
85
  namespace: string;
58
- manifest: unknown;
86
+ manifest?: unknown;
59
87
  fetchImpl?: typeof globalThis.fetch;
60
88
  jsonScalars?: FunctionOrmJsonScalars;
61
89
  }
62
- declare function createFunctionOrmExecutor({ request, fetchImpl, ...options }: FunctionOrmExecutorOptions): OperationExecutor;
63
- declare function createFunctionServiceOrmExecutor({ request, fetchImpl, ...options }: FunctionOrmExecutorOptions): OperationExecutor;
90
+ declare function createFunctionOrmExecutor({ request, fetchImpl, ...options }: FunctionOrmExecutorOptions): SqlOperationExecutor;
91
+ declare function createFunctionServiceOrmExecutor({ request, fetchImpl, ...options }: FunctionOrmExecutorOptions): SqlOperationExecutor;
64
92
 
65
- export { FunctionOrmError, type FunctionOrmErrorCode, type FunctionOrmExecutorOptions, type FunctionOrmJsonScalars, type FunctionOrmRequest, ORM_JSON_SCALARS_HEADER, ORM_LOSSLESS_JSON_SCALARS, type OperationExecutor, type OperationsManifest, OrmClientError, OrmOperationError, createFunctionOrmExecutor, createFunctionServiceOrmExecutor };
93
+ export { FunctionOrmError, type FunctionOrmErrorCode, type FunctionOrmExecutorOptions, type FunctionOrmJsonScalars, type FunctionOrmRequest, ORM_JSON_SCALARS_HEADER, ORM_LOSSLESS_JSON_SCALARS, type OperationExecutor, type OperationsManifest, OrmClientError, OrmOperationError, type SqlOperationExecutor, createFunctionOrmExecutor, createFunctionServiceOrmExecutor };
package/dist/orm.js CHANGED
@@ -82,6 +82,7 @@ function readOperationResponse({
82
82
  }
83
83
  return payload.data;
84
84
  }
85
+ var BUILTIN_SQL_READ_HASH = "sha256:a50c477c952a5e0fe68ed158a4530e4aab573c09bcbb1a8ac454dc88a39a6258";
85
86
  function validateIdempotencyKey(key) {
86
87
  if (key !== void 0 && !/^[A-Za-z0-9._:-]{1,128}$/.test(key)) {
87
88
  throw new OrmClientError("idempotencyKey must be 1\u2013128 letters, digits, dots, underscores, colons or hyphens");
@@ -103,13 +104,13 @@ function readManifestHashes(manifest) {
103
104
  }
104
105
  function createOperationExecutorWithTransport({ namespace, manifest, transport }) {
105
106
  if (typeof namespace !== "string" || !NAMESPACE_PATTERN.test(namespace)) throw new OrmClientError("invalid ORM namespace \u2014 expected a lowercase identifier of at most 41 characters");
106
- const hashes = readManifestHashes(manifest);
107
+ const hashes = manifest === void 0 ? /* @__PURE__ */ new Map() : readManifestHashes(manifest);
107
108
  const knownHashes = new Set(hashes.values());
108
109
  async function execute(op, variables = {}, options = {}) {
109
110
  validateIdempotencyKey(options.idempotencyKey);
110
111
  if (typeof op !== "string" && op.namespace !== namespace) throw new OrmClientError("operation belongs to a different namespace");
111
112
  const selector = typeof op === "string" ? op : op.hash;
112
- const hash = hashes.get(selector) ?? (knownHashes.has(selector) ? selector : void 0);
113
+ const hash = selector === BUILTIN_SQL_READ_HASH ? selector : hashes.get(selector) ?? (knownHashes.has(selector) ? selector : void 0);
113
114
  if (!hash) throw new OrmClientError(`unknown operation "${op}" \u2014 not in the manifest (${hashes.size} known). Re-run seq-studio orm generate.`);
114
115
  if (!isRecord(variables)) throw new OrmClientError("operation variables must be an object");
115
116
  const response = await transport({
@@ -123,7 +124,7 @@ function createOperationExecutorWithTransport({ namespace, manifest, transport }
123
124
  }
124
125
  return readOperationResponse(response);
125
126
  }
126
- return { execute };
127
+ return { execute, sql: (variables) => execute(BUILTIN_SQL_READ_HASH, variables) };
127
128
  }
128
129
 
129
130
  // src/orm.ts
@@ -0,0 +1,11 @@
1
+ import type { CapabilityTooling, PreflightIssue } from './capabilities';
2
+ export declare function createPreflightIssue({ field, problem, limit, tooling, requiredCli, requiredSdk, cliVersion, sdkVersion, }: {
3
+ field: string;
4
+ problem: string;
5
+ limit: string;
6
+ tooling: CapabilityTooling;
7
+ requiredCli: string;
8
+ requiredSdk: string;
9
+ cliVersion: string;
10
+ sdkVersion: string | null;
11
+ }): PreflightIssue;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPreflightIssue = createPreflightIssue;
4
+ function createPreflightIssue({ field, problem, limit, tooling, requiredCli, requiredSdk, cliVersion, sdkVersion, }) {
5
+ const installedSdk = sdkVersion ?? 'not declared';
6
+ return {
7
+ field,
8
+ limit,
9
+ requiredCli,
10
+ requiredSdk,
11
+ message: `${field}: ${problem} Supported limit: ${limit}. ` +
12
+ `Requires ${tooling.cli.package} >= ${requiredCli} (installed ${cliVersion}) ` +
13
+ `and ${tooling.sdk.package} >= ${requiredSdk} (installed ${installedSdk}).`,
14
+ };
15
+ }
@@ -0,0 +1,10 @@
1
+ import { type CapabilityTooling, type ManagedFunctionCapabilities, type PreflightIssue, type PreflightManifest } from './capabilities';
2
+ export declare function checkProcesses({ manifest, capabilities, tooling, cliVersion, sdkVersion, checkDeployment, issues, }: {
3
+ manifest: PreflightManifest;
4
+ capabilities: ManagedFunctionCapabilities | null;
5
+ tooling: CapabilityTooling;
6
+ cliVersion: string;
7
+ sdkVersion: string | null;
8
+ checkDeployment: boolean;
9
+ issues: PreflightIssue[];
10
+ }): void;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkProcesses = checkProcesses;
4
+ const capabilities_1 = require("./capabilities");
5
+ const preflight_issue_1 = require("./preflight-issue");
6
+ const processes_contract_1 = require("./processes-contract");
7
+ const sdk_range_1 = require("./sdk-range");
8
+ function checkProcesses({ manifest, capabilities, tooling, cliVersion, sdkVersion, checkDeployment, issues, }) {
9
+ const processes = manifest.capabilities?.processes;
10
+ if (processes === undefined)
11
+ return;
12
+ const deployedFeature = capabilities?.features.processes_read;
13
+ const feature = deployedFeature ?? capabilities_1.MANAGED_FUNCTION_CAPABILITIES.features.processes_read;
14
+ const details = {
15
+ limit: feature.limit,
16
+ tooling,
17
+ requiredCli: feature.min_cli,
18
+ requiredSdk: feature.min_sdk,
19
+ cliVersion,
20
+ sdkVersion,
21
+ };
22
+ const parsed = processes_contract_1.functionProcessReadScopesSchema.safeParse(processes);
23
+ if (!parsed.success) {
24
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
25
+ ...details,
26
+ field: 'capabilities.processes',
27
+ problem: (0, capabilities_1.formatValidationDetail)(parsed.error.issues),
28
+ }));
29
+ return;
30
+ }
31
+ if (checkDeployment && deployedFeature?.supported !== true) {
32
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
33
+ ...details,
34
+ field: feature.field,
35
+ problem: 'process reads are not supported by this deployment',
36
+ }));
37
+ return;
38
+ }
39
+ if ((0, capabilities_1.versionIsOlder)(cliVersion, feature.min_cli) || (sdkVersion && (0, sdk_range_1.sdkConstraintIsOlder)(sdkVersion, feature.min_sdk))) {
40
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
41
+ ...details,
42
+ field: feature.field,
43
+ problem: 'the installed tooling does not support managed function process reads',
44
+ }));
45
+ }
46
+ }
@@ -1,9 +1,10 @@
1
1
  import type { ManagedFunctionLimitCatalog } from './limits';
2
2
  import { type ManagedFunctionCapabilities, type PreflightIssue, type PreflightManifest } from './capabilities';
3
- export declare function preflightManagedFunction({ manifest, limits, capabilities, cliVersion, sdkVersion, }: {
3
+ export declare function preflightManagedFunction({ manifest, limits, capabilities, cliVersion, sdkVersion, checkDeployment, }: {
4
4
  manifest: PreflightManifest;
5
5
  limits: ManagedFunctionLimitCatalog | null;
6
6
  capabilities: ManagedFunctionCapabilities | null;
7
7
  cliVersion: string;
8
8
  sdkVersion: string | null;
9
+ checkDeployment?: boolean;
9
10
  }): PreflightIssue[];
package/dist/preflight.js CHANGED
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.preflightManagedFunction = preflightManagedFunction;
4
4
  const capabilities_1 = require("./capabilities");
5
5
  const sdk_range_1 = require("./sdk-range");
6
+ const preflight_issue_1 = require("./preflight-issue");
7
+ const preflight_processes_1 = require("./preflight-processes");
8
+ const processes_contract_1 = require("./processes-contract");
6
9
  const WORKLOAD_FIELDS = [
7
10
  'memory_mb',
8
11
  'timeout_seconds',
@@ -12,27 +15,16 @@ const WORKLOAD_FIELDS = [
12
15
  'max_response_bytes',
13
16
  'concurrency',
14
17
  ];
15
- function preflightManagedFunction({ manifest, limits, capabilities, cliVersion, sdkVersion, }) {
18
+ function preflightManagedFunction({ manifest, limits, capabilities, cliVersion, sdkVersion, checkDeployment = true, }) {
16
19
  const tooling = capabilities?.tooling ?? capabilities_1.MANAGED_FUNCTION_CAPABILITIES.tooling;
17
20
  const issues = [];
18
21
  checkWorkload({ manifest, limits, tooling, cliVersion, sdkVersion, issues });
19
22
  checkPostgres({ manifest, capabilities, tooling, cliVersion, sdkVersion, issues });
23
+ (0, preflight_processes_1.checkProcesses)({ manifest, capabilities, tooling, cliVersion, sdkVersion, checkDeployment, issues });
20
24
  checkHeaders({ manifest, capabilities, tooling, cliVersion, sdkVersion, issues });
21
25
  checkSdkTimeout({ manifest, limits, capabilities, tooling, cliVersion, sdkVersion, issues });
22
26
  return issues;
23
27
  }
24
- function issue({ field, problem, limit, tooling, requiredCli, requiredSdk, cliVersion, sdkVersion, }) {
25
- const installedSdk = sdkVersion ?? 'not declared';
26
- return {
27
- field,
28
- limit,
29
- requiredCli,
30
- requiredSdk,
31
- message: `${field}: ${problem} Supported limit: ${limit}. ` +
32
- `Requires ${tooling.cli.package} >= ${requiredCli} (installed ${cliVersion}) ` +
33
- `and ${tooling.sdk.package} >= ${requiredSdk} (installed ${installedSdk}).`,
34
- };
35
- }
36
28
  function numericCap(entry) {
37
29
  if (!entry || typeof entry !== 'object')
38
30
  return null;
@@ -60,7 +52,7 @@ function checkWorkload({ manifest, limits, tooling, cliVersion, sdkVersion, issu
60
52
  if (Number.isInteger(value) && value >= cap.min && value <= cap.max)
61
53
  continue;
62
54
  const unit = cap.unit ? ` ${cap.unit}` : '';
63
- issues.push(issue({
55
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
64
56
  field: `limits.${name}`,
65
57
  problem: `${value} is outside the range this deployment enforces`,
66
58
  limit: `${cap.min} to ${cap.max}${unit}`,
@@ -77,7 +69,7 @@ function checkWorkload({ manifest, limits, tooling, cliVersion, sdkVersion, issu
77
69
  return;
78
70
  if (typeof cpu === 'number' && Number.isInteger(cpu) && cpu >= cpuCap.min && cpu <= cpuCap.max)
79
71
  return;
80
- issues.push(issue({
72
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
81
73
  field: 'limits.cpu',
82
74
  problem: `${String(cpu)} is outside the range this deployment enforces`,
83
75
  limit: `${cpuCap.min} to ${cpuCap.max}, or auto`,
@@ -98,7 +90,7 @@ function checkPostgres({ manifest, capabilities, tooling, cliVersion, sdkVersion
98
90
  return;
99
91
  const field = `egress[${index}]`;
100
92
  if (!feature.supported) {
101
- issues.push(issue({
93
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
102
94
  field,
103
95
  problem: 'PostgreSQL egress is not supported by this deployment',
104
96
  limit: 'hostnames, http(s) URLs, and public IPv4 CIDRs',
@@ -111,7 +103,7 @@ function checkPostgres({ manifest, capabilities, tooling, cliVersion, sdkVersion
111
103
  return;
112
104
  }
113
105
  if ((0, capabilities_1.versionIsOlder)(cliVersion, feature.min_cli)) {
114
- issues.push(issue({
106
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
115
107
  field,
116
108
  problem: 'this CLI rejects PostgreSQL egress that this deployment supports',
117
109
  limit: feature.limit,
@@ -129,7 +121,8 @@ function needsWideHeaders(manifest) {
129
121
  const storage = manifest.capabilities?.storage;
130
122
  const hasData = !!data && Object.keys(data).length > 0;
131
123
  const hasStorage = !!storage && typeof storage === 'object' && Object.keys(storage).length > 0;
132
- return hasData || hasStorage;
124
+ const hasProcesses = processes_contract_1.functionProcessReadScopesSchema.safeParse(manifest.capabilities?.processes).success;
125
+ return hasData || hasStorage || hasProcesses;
133
126
  }
134
127
  function checkHeaders({ manifest, capabilities, tooling, cliVersion, sdkVersion, issues, }) {
135
128
  const feature = capabilities?.features.http_headers;
@@ -138,9 +131,9 @@ function checkHeaders({ manifest, capabilities, tooling, cliVersion, sdkVersion,
138
131
  const supported = capabilities_1.MANAGED_FUNCTION_CAPABILITIES.features.http_headers.max_bytes;
139
132
  if (feature.max_bytes >= supported)
140
133
  return;
141
- issues.push(issue({
134
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
142
135
  field: feature.field,
143
- problem: `invocation headers for capabilities.data or capabilities.storage exceed ${feature.max_bytes} bytes and will fail with HTTP 431`,
136
+ problem: `invocation headers for capabilities.data, capabilities.storage, or capabilities.processes exceed ${feature.max_bytes} bytes and will fail with HTTP 431`,
144
137
  limit: feature.limit,
145
138
  tooling,
146
139
  requiredCli: feature.min_cli,
@@ -159,7 +152,7 @@ function checkSdkTimeout({ manifest, limits, capabilities, tooling, cliVersion,
159
152
  if (timeout <= feature.legacy_sdk_max_seconds)
160
153
  return;
161
154
  const platformMax = numericCap(limits?.workload?.timeout_seconds)?.max ?? feature.max_seconds;
162
- issues.push(issue({
155
+ issues.push((0, preflight_issue_1.createPreflightIssue)({
163
156
  field: feature.field,
164
157
  problem: `${timeout} seconds exceeds the installed SDK's ${feature.legacy_sdk_max_seconds} second client cap, behind the platform limit of ${platformMax} seconds`,
165
158
  limit: feature.limit,
@@ -0,0 +1,109 @@
1
+ import { z } from 'zod';
2
+ export declare const FUNCTION_PROCESS_TOKEN_HEADER = "x-sequence-process-service-token";
3
+ export declare const FUNCTION_PROCESS_READ_PATH = "/api/managed-functions/processes/read";
4
+ export declare const functionProcessReadScopesSchema: z.ZodObject<{
5
+ read: z.ZodArray<z.ZodString>;
6
+ }, z.core.$strict>;
7
+ export declare function readFunctionProcessScopes(manifest: unknown): string[];
8
+ export declare const functionProcessRunStatusSchema: z.ZodEnum<{
9
+ pending: "pending";
10
+ running: "running";
11
+ completed: "completed";
12
+ failed: "failed";
13
+ cancelled: "cancelled";
14
+ timed_out: "timed_out";
15
+ }>;
16
+ export type FunctionProcessRunStatus = z.infer<typeof functionProcessRunStatusSchema>;
17
+ export declare const functionProcessRunSummarySchema: z.ZodObject<{
18
+ id: z.ZodString;
19
+ processId: z.ZodString;
20
+ status: z.ZodEnum<{
21
+ pending: "pending";
22
+ running: "running";
23
+ completed: "completed";
24
+ failed: "failed";
25
+ cancelled: "cancelled";
26
+ timed_out: "timed_out";
27
+ }>;
28
+ entityType: z.ZodNullable<z.ZodString>;
29
+ entityId: z.ZodNullable<z.ZodString>;
30
+ startedAt: z.ZodISODateTime;
31
+ completedAt: z.ZodNullable<z.ZodISODateTime>;
32
+ }, z.core.$strip>;
33
+ export type FunctionProcessRunSummary = z.infer<typeof functionProcessRunSummarySchema>;
34
+ export declare const functionProcessRunQuerySchema: z.ZodObject<{
35
+ process: z.ZodString;
36
+ runId: z.ZodString;
37
+ }, z.core.$strict>;
38
+ export declare const functionProcessRunsPageQuerySchema: z.ZodObject<{
39
+ process: z.ZodString;
40
+ statuses: z.ZodOptional<z.ZodArray<z.ZodEnum<{
41
+ pending: "pending";
42
+ running: "running";
43
+ completed: "completed";
44
+ failed: "failed";
45
+ cancelled: "cancelled";
46
+ timed_out: "timed_out";
47
+ }>>>;
48
+ entity: z.ZodOptional<z.ZodObject<{
49
+ type: z.ZodString;
50
+ id: z.ZodOptional<z.ZodString>;
51
+ ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
52
+ }, z.core.$strict>>;
53
+ limit: z.ZodOptional<z.ZodNumber>;
54
+ cursor: z.ZodOptional<z.ZodString>;
55
+ archived: z.ZodOptional<z.ZodBoolean>;
56
+ }, z.core.$strict>;
57
+ export type FunctionProcessRunQuery = z.infer<typeof functionProcessRunQuerySchema>;
58
+ export type FunctionProcessRunsPageQuery = z.infer<typeof functionProcessRunsPageQuerySchema>;
59
+ export declare const functionProcessRunsPageSchema: z.ZodObject<{
60
+ runs: z.ZodArray<z.ZodObject<{
61
+ id: z.ZodString;
62
+ processId: z.ZodString;
63
+ status: z.ZodEnum<{
64
+ pending: "pending";
65
+ running: "running";
66
+ completed: "completed";
67
+ failed: "failed";
68
+ cancelled: "cancelled";
69
+ timed_out: "timed_out";
70
+ }>;
71
+ entityType: z.ZodNullable<z.ZodString>;
72
+ entityId: z.ZodNullable<z.ZodString>;
73
+ startedAt: z.ZodISODateTime;
74
+ completedAt: z.ZodNullable<z.ZodISODateTime>;
75
+ }, z.core.$strip>>;
76
+ nextCursor: z.ZodNullable<z.ZodString>;
77
+ }, z.core.$strip>;
78
+ export type FunctionProcessRunsPage = z.infer<typeof functionProcessRunsPageSchema>;
79
+ export declare const functionProcessReadRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
80
+ process: z.ZodString;
81
+ runId: z.ZodString;
82
+ operation: z.ZodLiteral<"getRun">;
83
+ }, z.core.$strict>, z.ZodObject<{
84
+ process: z.ZodString;
85
+ statuses: z.ZodOptional<z.ZodArray<z.ZodEnum<{
86
+ pending: "pending";
87
+ running: "running";
88
+ completed: "completed";
89
+ failed: "failed";
90
+ cancelled: "cancelled";
91
+ timed_out: "timed_out";
92
+ }>>>;
93
+ entity: z.ZodOptional<z.ZodObject<{
94
+ type: z.ZodString;
95
+ id: z.ZodOptional<z.ZodString>;
96
+ ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
97
+ }, z.core.$strict>>;
98
+ limit: z.ZodOptional<z.ZodNumber>;
99
+ cursor: z.ZodOptional<z.ZodString>;
100
+ archived: z.ZodOptional<z.ZodBoolean>;
101
+ operation: z.ZodLiteral<"listRunsPage">;
102
+ }, z.core.$strict>], "operation">;
103
+ export type FunctionProcessReadRequest = z.infer<typeof functionProcessReadRequestSchema>;
104
+ export declare class FunctionProcessReadError extends Error {
105
+ readonly status: number;
106
+ readonly code: string;
107
+ readonly name = "FunctionProcessReadError";
108
+ constructor(status: number, code: string, message: string);
109
+ }