@sequenceholdings/managed-functions 0.4.3 → 0.4.5

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
@@ -324,6 +324,20 @@ const page = await processes.listRunsPage({
324
324
  })
325
325
  ```
326
326
 
327
+ The SDK 0.4.4 / CLI 0.6.6 release candidates (awaiting publication) add
328
+ `processes.getCompletedNode({ process, runId, nodeId })`. It returns only
329
+ `{ runId, processId, processVersion, nodeId, stepId, completedAt }` after both
330
+ the run and its latest top-level step have committed successfully. The exact
331
+ node must have no outgoing edges in the run's immutable pinned bundle. The
332
+ existing invocation-bound process scope and current Process/Run Viewer grants
333
+ apply. Historical successful steps in running, cancelled or failed runs,
334
+ parallel child steps, and ambiguous serial positions are refused with
335
+ `409 node_not_completed`; workers can retry without sending their side effect.
336
+ The caller must separately check its expected process version and allowed
337
+ terminal node. No authored metadata, state or output is exposed. This method
338
+ requires the matching server deployment; the older `processes_read` capability
339
+ alone does not advertise support for this new operation.
340
+
327
341
  With SDK 0.4.2 and both exact process and agent read declarations,
328
342
  `processes.getCompletedAgentReference({ process, runId, nodeId })` recovers only
329
343
  `{ stepId, attempt, agentId, agentRunId, threadId }` for a unique completed
@@ -451,6 +465,21 @@ const invocation = createFunctionInvocationClient({ request, baseUrl: platformOr
451
465
  const { receiver, caller } = await invocation.getInvocationContext()
452
466
  ```
453
467
 
468
+ With `capabilities.invocation: { identity: true, caller_capabilities: true }`,
469
+ `invocation.getCallerCapabilities()` returns `{ receiver, caller, capabilities }`.
470
+ It accepts no subject or host selector. Atlas rechecks the exact live invocation,
471
+ receiver/version and current human caller, resolves that caller's function
472
+ access and custom-role grants, and intersects the result with the receiver's
473
+ current declared capability vocabulary (at most 256 pins). Service/system
474
+ callers are refused; this method cannot borrow a run starter or attached
475
+ service account's grants. Revoked or undeclared grants are absent, and failures
476
+ never supply capability authority. It does not accept unsigned claim headers.
477
+
478
+ This opt-in requires deployed `invocation_caller_capabilities` support, SDK
479
+ 0.4.4 and CLI 0.6.6. Identity-only manifests retain their previous behavior.
480
+ Do not cache this current observation as a lasting grant or expose the
481
+ invocation credential to a browser.
482
+
454
483
  The receiver identifies this function, version, invocation, organization and
455
484
  attached service account. The caller is the authenticated human, service
456
485
  account or system principal that invoked it; the attached account and a
@@ -506,6 +535,16 @@ or context metadata are never substitutes. Older runs may omit this field or
506
535
  return `null`. A start stamp records the original admission decision, rather
507
536
  than granting current permissions or identifying a later human action.
508
537
 
538
+ `getRunCreatorAccess()` returns current, invocation-bound evidence for the
539
+ retained signed run starter: `{ creator: { sub, tenant, platformOperator } | null,
540
+ observedAt, ...executionIdentity }`. The platform resolves a current active human
541
+ and evaluates its shared operator policy; app-authored metadata and email domains
542
+ cannot establish this authority. Missing provenance, deleted/disabled identities,
543
+ or ambiguous aliases return `creator: null`; directory outages fail the request.
544
+ Operator evaluation retains the shared platform policy, including its FGA cache
545
+ and configured legacy-role fallback; this is not instantaneous role revocation. This is a current observation, not an impersonation credential or a
546
+ replacement for business authorization. It accepts no subject or run selector.
547
+
509
548
  Human reads verify a platform-signed receipt against the actual completed step,
510
549
  current receiving invocation, frozen graph and causal subprocess lineage. The
511
550
  caller must still check the expected action, task, approval generation and
@@ -770,3 +809,48 @@ Successful reads of a Lattice process or run link to the owning process; direct
770
809
  HTTP run starts already use server-recorded spans and preserve the request chain.
771
810
  Transport classification is shared with the platform host; function authors
772
811
  do not need to import or configure instrumentation.
812
+
813
+ ## Scoped service group rosters
814
+
815
+ `createFunctionServiceDirectoryClient().listGroupMembers()` reads bounded pages
816
+ of active members of explicitly declared groups. It requires Managed Functions
817
+ SDK 0.4.4, Studio CLI 0.6.6, and a host advertising `directory_rosters`.
818
+
819
+ ```yaml
820
+ service_account: notification-worker
821
+ capabilities:
822
+ directory:
823
+ resolve: [banksouth]
824
+ rosters: ["11111111-1111-4111-8111-111111111111"]
825
+ ```
826
+
827
+ ```ts
828
+ const directory = createFunctionServiceDirectoryClient({ request, baseUrl })
829
+ let cursor: string | undefined
830
+ do {
831
+ const page = await directory.listGroupMembers({
832
+ tenant: 'banksouth', groupId, limit: 50, cursor,
833
+ })
834
+ await consume(page.members)
835
+ cursor = page.nextCursor ?? undefined
836
+ } while (cursor)
837
+ ```
838
+
839
+ The manifest permits at most 16 concrete group IDs. It does not grant access:
840
+ the attached service account independently needs the tenant directory's Reader
841
+ relation and the group's Member relation (direct membership or the group's Owner
842
+ relation). Organization or application administration is not a fallback. The
843
+ actual attached account is checked on every page; the invoking human/system
844
+ identity never supplies its grants. No user-mode directory API gains service mode.
845
+
846
+ Atlas intersects the signed invocation's groups with the current function
847
+ manifest, verifies the live function/version/account/invocation, and checks both
848
+ grants again before reading. Deleted groups and inactive, deleted, or foreign
849
+ tenant users are excluded. The caller cannot request inactive identities or
850
+ choose another principal. Results contain only `id`, `sub`, `name`, `email`, and
851
+ `deactivated: false`. Membership is read live, not as a transaction-wide snapshot.
852
+
853
+ Pagination scans membership positions, so a page may have zero members and a
854
+ non-null `nextCursor`; continue until the cursor is null. Cursors expire after an
855
+ hour and bind the tenant, group, function, immutable version and service account.
856
+ They cannot be moved to another read scope. Access can be revoked between pages.
@@ -13,6 +13,13 @@ export declare const MANAGED_FUNCTION_CAPABILITIES: {
13
13
  };
14
14
  };
15
15
  readonly features: {
16
+ readonly directory_rosters: {
17
+ readonly field: "capabilities.directory.rosters";
18
+ readonly supported: true;
19
+ readonly limit: "1 to 16 explicit groups; up to 50 active tenant members per page; directory Reader and group membership required";
20
+ readonly min_cli: "0.6.6";
21
+ readonly min_sdk: "0.4.4";
22
+ };
16
23
  readonly directory_members: {
17
24
  readonly field: "capabilities.directory.groups";
18
25
  readonly supported: true;
@@ -34,6 +41,13 @@ export declare const MANAGED_FUNCTION_CAPABILITIES: {
34
41
  readonly min_cli: "0.5.5";
35
42
  readonly min_sdk: "0.4.2";
36
43
  };
44
+ readonly invocation_caller_capabilities: {
45
+ readonly field: "capabilities.invocation.caller_capabilities";
46
+ readonly supported: true;
47
+ readonly limit: "current human caller capabilities declared by this exact active receiver; at most 256 pins";
48
+ readonly min_cli: "0.6.6";
49
+ readonly min_sdk: "0.4.4";
50
+ };
37
51
  readonly invocation_identity: {
38
52
  readonly field: "capabilities.invocation.identity";
39
53
  readonly supported: true;
@@ -134,6 +148,13 @@ export interface CapabilityTooling {
134
148
  export interface ManagedFunctionCapabilities {
135
149
  tooling: CapabilityTooling;
136
150
  features: {
151
+ directory_rosters?: {
152
+ field: string;
153
+ supported: boolean;
154
+ limit: string;
155
+ min_cli: string;
156
+ min_sdk: string;
157
+ };
137
158
  directory_members?: {
138
159
  field: string;
139
160
  supported: boolean;
@@ -155,6 +176,13 @@ export interface ManagedFunctionCapabilities {
155
176
  min_cli: string;
156
177
  min_sdk: string;
157
178
  };
179
+ invocation_caller_capabilities?: {
180
+ field: string;
181
+ supported: boolean;
182
+ limit: string;
183
+ min_cli: string;
184
+ min_sdk: string;
185
+ };
158
186
  invocation_identity?: {
159
187
  field: string;
160
188
  supported: boolean;
@@ -16,6 +16,7 @@ exports.MANAGED_FUNCTION_CAPABILITIES = {
16
16
  sdk: { package: exports.MANAGED_FUNCTION_SDK_PACKAGE, min: '0.3.0' },
17
17
  },
18
18
  features: {
19
+ directory_rosters: { field: 'capabilities.directory.rosters', supported: true, limit: '1 to 16 explicit groups; up to 50 active tenant members per page; directory Reader and group membership required', min_cli: '0.6.6', min_sdk: '0.4.4' },
19
20
  directory_members: {
20
21
  field: 'capabilities.directory.groups', supported: true,
21
22
  limit: '1 to 16 concrete groups; resolve 1 to 50 selected active members per call',
@@ -31,6 +32,11 @@ exports.MANAGED_FUNCTION_CAPABILITIES = {
31
32
  limit: 'a fresh function identity whose runtime cannot be redeployed after first activation',
32
33
  min_cli: '0.5.5', min_sdk: '0.4.2',
33
34
  },
35
+ invocation_caller_capabilities: {
36
+ field: 'capabilities.invocation.caller_capabilities', supported: true,
37
+ limit: 'current human caller capabilities declared by this exact active receiver; at most 256 pins',
38
+ min_cli: '0.6.6', min_sdk: '0.4.4',
39
+ },
34
40
  invocation_identity: {
35
41
  field: 'capabilities.invocation.identity', supported: true,
36
42
  limit: 'verified receiver and actual caller for this exact active invocation only',
package/dist/config.d.ts CHANGED
@@ -2,7 +2,7 @@ export { DIRECTORY_TOKEN_HEADER, directoryGroupIdSchema, directoryScopesSchema,
2
2
  export { functionDirectoryManifestSchema } from './directory-manifest';
3
3
  export { functionLatticeContextCapabilitySchema, readFunctionLatticeContextCapability } from './lattice-capability';
4
4
  export * from './invocation-contract';
5
- export { FUNCTION_PROCESS_TOKEN_HEADER, FUNCTION_PROCESS_READ_PATH, functionProcessReadScopesSchema, readFunctionProcessScopes, functionProcessReadRequestSchema, functionProcessRunSummarySchema, functionProcessCompletedAgentReferenceSchema, functionProcessCompletedAgentReferenceQuerySchema } from './processes-contract';
5
+ export { FUNCTION_PROCESS_TOKEN_HEADER, FUNCTION_PROCESS_READ_PATH, functionProcessReadScopesSchema, readFunctionProcessScopes, functionProcessReadRequestSchema, functionProcessRunSummarySchema, functionProcessCompletedAgentReferenceSchema, functionProcessCompletedAgentReferenceQuerySchema, functionProcessCompletedNodeSchema, functionProcessCompletedNodeQuerySchema } from './processes-contract';
6
6
  export { FUNCTION_AGENT_TOKEN_HEADER, FUNCTION_AGENT_READ_PATH, functionAgentReadScopesSchema, readFunctionAgentScopes, functionAgentReadRequestSchema, functionAgentCompletedRunQuerySchema, functionAgentCompletedRunSchema } from './agents-contract';
7
7
  export * from './agent-source-evidence-contract';
8
8
  export * from './workflow-source-contract';
@@ -36,3 +36,4 @@ export declare const cacheManifestSchema: z.ZodObject<{
36
36
  }, z.core.$strict>;
37
37
  export type CacheConfiguration = z.infer<typeof cacheManifestSchema>;
38
38
  export declare function readCacheConfiguration(manifest: unknown): CacheConfiguration;
39
+ export * from './directory-roster-contract';
package/dist/config.js CHANGED
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.versionIsOlder = exports.sdkVersionLowerBound = exports.sdkSpecFromPackageJson = 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.readFunctionImmutableRelease = exports.functionImmutableReleaseSchema = exports.shouldReportAtlasHttp = exports.directoryPrincipalResolutionSchema = exports.directoryPrincipalResolveRequestSchema = exports.readFunctionDirectoryScopes = exports.functionDirectoryScopesSchema = exports.FUNCTION_DIRECTORY_RESOLVE_PATH = exports.FUNCTION_DIRECTORY_TOKEN_HEADER = exports.FUNCTION_CALLER_DATA_TOKEN_HEADER = exports.readFunctionWorkflowEvidenceScopes = exports.readFunctionWorkflowScopes = exports.functionWorkflowScopesSchema = exports.functionAgentCompletedRunSchema = exports.functionAgentCompletedRunQuerySchema = exports.functionAgentReadRequestSchema = exports.readFunctionAgentScopes = exports.functionAgentReadScopesSchema = exports.FUNCTION_AGENT_READ_PATH = exports.FUNCTION_AGENT_TOKEN_HEADER = exports.functionProcessCompletedAgentReferenceQuerySchema = exports.functionProcessCompletedAgentReferenceSchema = exports.functionProcessRunSummarySchema = exports.functionProcessReadRequestSchema = exports.readFunctionProcessScopes = exports.functionProcessReadScopesSchema = exports.FUNCTION_PROCESS_READ_PATH = exports.FUNCTION_PROCESS_TOKEN_HEADER = exports.readFunctionLatticeContextCapability = exports.functionLatticeContextCapabilitySchema = exports.functionDirectoryManifestSchema = exports.readDirectoryGroups = exports.directoryMembersResponse = exports.directoryMembersInput = exports.directoryScopesSchema = exports.directoryGroupIdSchema = exports.DIRECTORY_TOKEN_HEADER = void 0;
18
- exports.cacheManifestSchema = exports.CACHE_MAX_TTL_SECONDS = exports.preflightManagedFunction = exports.parseDeployedPolicy = void 0;
17
+ exports.sdkSpecFromPackageJson = 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.readFunctionImmutableRelease = exports.functionImmutableReleaseSchema = exports.shouldReportAtlasHttp = exports.directoryPrincipalResolutionSchema = exports.directoryPrincipalResolveRequestSchema = exports.readFunctionDirectoryScopes = exports.functionDirectoryScopesSchema = exports.FUNCTION_DIRECTORY_RESOLVE_PATH = exports.FUNCTION_DIRECTORY_TOKEN_HEADER = exports.FUNCTION_CALLER_DATA_TOKEN_HEADER = exports.readFunctionWorkflowEvidenceScopes = exports.readFunctionWorkflowScopes = exports.functionWorkflowScopesSchema = exports.functionAgentCompletedRunSchema = exports.functionAgentCompletedRunQuerySchema = exports.functionAgentReadRequestSchema = exports.readFunctionAgentScopes = exports.functionAgentReadScopesSchema = exports.FUNCTION_AGENT_READ_PATH = exports.FUNCTION_AGENT_TOKEN_HEADER = exports.functionProcessCompletedNodeQuerySchema = exports.functionProcessCompletedNodeSchema = exports.functionProcessCompletedAgentReferenceQuerySchema = exports.functionProcessCompletedAgentReferenceSchema = exports.functionProcessRunSummarySchema = exports.functionProcessReadRequestSchema = exports.readFunctionProcessScopes = exports.functionProcessReadScopesSchema = exports.FUNCTION_PROCESS_READ_PATH = exports.FUNCTION_PROCESS_TOKEN_HEADER = exports.readFunctionLatticeContextCapability = exports.functionLatticeContextCapabilitySchema = exports.functionDirectoryManifestSchema = exports.readDirectoryGroups = exports.directoryMembersResponse = exports.directoryMembersInput = exports.directoryScopesSchema = exports.directoryGroupIdSchema = exports.DIRECTORY_TOKEN_HEADER = void 0;
18
+ exports.cacheManifestSchema = exports.CACHE_MAX_TTL_SECONDS = exports.preflightManagedFunction = exports.parseDeployedPolicy = exports.versionIsOlder = exports.sdkVersionLowerBound = void 0;
19
19
  exports.readCacheConfiguration = readCacheConfiguration;
20
20
  var directory_config_1 = require("./directory-config");
21
21
  Object.defineProperty(exports, "DIRECTORY_TOKEN_HEADER", { enumerable: true, get: function () { return directory_config_1.DIRECTORY_TOKEN_HEADER; } });
@@ -39,6 +39,8 @@ Object.defineProperty(exports, "functionProcessReadRequestSchema", { enumerable:
39
39
  Object.defineProperty(exports, "functionProcessRunSummarySchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessRunSummarySchema; } });
40
40
  Object.defineProperty(exports, "functionProcessCompletedAgentReferenceSchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedAgentReferenceSchema; } });
41
41
  Object.defineProperty(exports, "functionProcessCompletedAgentReferenceQuerySchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedAgentReferenceQuerySchema; } });
42
+ Object.defineProperty(exports, "functionProcessCompletedNodeSchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedNodeSchema; } });
43
+ Object.defineProperty(exports, "functionProcessCompletedNodeQuerySchema", { enumerable: true, get: function () { return processes_contract_1.functionProcessCompletedNodeQuerySchema; } });
42
44
  var agents_contract_1 = require("./agents-contract");
43
45
  Object.defineProperty(exports, "FUNCTION_AGENT_TOKEN_HEADER", { enumerable: true, get: function () { return agents_contract_1.FUNCTION_AGENT_TOKEN_HEADER; } });
44
46
  Object.defineProperty(exports, "FUNCTION_AGENT_READ_PATH", { enumerable: true, get: function () { return agents_contract_1.FUNCTION_AGENT_READ_PATH; } });
@@ -115,3 +117,4 @@ function readCacheConfiguration(manifest) {
115
117
  : undefined;
116
118
  return exports.cacheManifestSchema.parse(cache ?? {});
117
119
  }
120
+ __exportStar(require("./directory-roster-contract"), exports);
@@ -40,8 +40,10 @@ function normalizeCapabilities(value) {
40
40
  features: {
41
41
  immutable_release: normalizeImmutableRelease(features.immutable_release),
42
42
  invocation_identity: normalizeInvocationIdentity(features.invocation_identity),
43
+ invocation_caller_capabilities: normalizeInvocationIdentity(features.invocation_caller_capabilities, 'capabilities.invocation.caller_capabilities'),
43
44
  directory_members: normalizeDirectoryMembers(features.directory_members),
44
45
  directory_resolve: normalizeDirectory(features.directory_resolve),
46
+ directory_rosters: normalizeRosters(features.directory_rosters),
45
47
  abrigo_read: normalizeAbrigo(features.abrigo_read),
46
48
  lattice_context: normalizeLatticeContext(features.lattice_context),
47
49
  postgres_egress: normalizePostgres(features.postgres_egress),
@@ -89,13 +91,13 @@ function normalizeAbrigo(value) {
89
91
  return undefined;
90
92
  return { field: typeof value.field === 'string' ? value.field : 'capabilities.abrigo.read', supported: value.supported, limit: value.limit, min_cli: value.min_cli, min_sdk: value.min_sdk };
91
93
  }
92
- function normalizeInvocationIdentity(value) {
94
+ function normalizeInvocationIdentity(value, defaultField = 'capabilities.invocation.identity') {
93
95
  if (!value || typeof value.supported !== 'boolean' || typeof value.limit !== 'string')
94
96
  return undefined;
95
97
  if (typeof value.min_cli !== 'string' || typeof value.min_sdk !== 'string')
96
98
  return undefined;
97
99
  return {
98
- field: typeof value.field === 'string' ? value.field : 'capabilities.invocation.identity',
100
+ field: typeof value.field === 'string' ? value.field : defaultField,
99
101
  supported: value.supported, limit: value.limit, min_cli: value.min_cli, min_sdk: value.min_sdk,
100
102
  };
101
103
  }
@@ -202,3 +204,8 @@ function normalizeTimeout(value) {
202
204
  min_sdk: value.min_sdk,
203
205
  };
204
206
  }
207
+ function normalizeRosters(value) {
208
+ if (!value || typeof value.supported !== 'boolean' || typeof value.limit !== 'string' || typeof value.min_cli !== 'string' || typeof value.min_sdk !== 'string')
209
+ return undefined;
210
+ return { field: typeof value.field === 'string' ? value.field : 'capabilities.directory.rosters', supported: value.supported, limit: value.limit, min_cli: value.min_cli, min_sdk: value.min_sdk };
211
+ }
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  export declare const functionDirectoryManifestSchema: z.ZodObject<{
3
+ rosters: z.ZodOptional<z.ZodArray<z.ZodString>>;
3
4
  groups: z.ZodOptional<z.ZodArray<z.ZodString>>;
4
5
  resolve: z.ZodOptional<z.ZodArray<z.ZodString>>;
5
6
  }, z.core.$strict>;
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.functionDirectoryManifestSchema = void 0;
4
+ const directory_roster_contract_1 = require("./directory-roster-contract");
4
5
  const zod_1 = require("zod");
5
6
  const directory_config_1 = require("./directory-config");
6
7
  const directory_contract_1 = require("./directory-contract");
7
8
  exports.functionDirectoryManifestSchema = zod_1.z.strictObject({
9
+ rosters: directory_roster_contract_1.functionDirectoryRostersSchema.optional(),
8
10
  groups: directory_config_1.directoryScopesSchema.shape.groups.optional(),
9
11
  resolve: directory_contract_1.functionDirectoryScopesSchema.shape.resolve.optional(),
10
- }).refine((value) => value.groups !== undefined || value.resolve !== undefined, 'Declare directory groups, tenant resolution scopes, or both');
12
+ }).refine((value) => value.groups !== undefined || value.resolve !== undefined, 'Declare directory groups, tenant resolution scopes, or both').refine(value => value.rosters === undefined || value.resolve !== undefined, 'Service rosters also require directory resolve tenant scopes');
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ export declare const FUNCTION_DIRECTORY_ROSTER_PATH = "/api/managed-functions/directory/roster";
3
+ export declare const functionDirectoryRostersSchema: z.ZodArray<z.ZodString>;
4
+ export declare const directoryRosterQuerySchema: z.ZodObject<{
5
+ tenant: z.ZodString;
6
+ groupId: z.ZodString;
7
+ limit: z.ZodDefault<z.ZodNumber>;
8
+ cursor: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strict>;
10
+ export declare const directoryRosterPageSchema: z.ZodObject<{
11
+ members: z.ZodArray<z.ZodObject<{
12
+ id: z.ZodString;
13
+ sub: z.ZodString;
14
+ name: z.ZodString;
15
+ email: z.ZodString;
16
+ deactivated: z.ZodLiteral<false>;
17
+ }, z.core.$strict>>;
18
+ nextCursor: z.ZodNullable<z.ZodString>;
19
+ }, z.core.$strict>;
20
+ export type DirectoryRosterQuery = z.input<typeof directoryRosterQuerySchema>;
21
+ export type DirectoryRosterPage = z.infer<typeof directoryRosterPageSchema>;
22
+ export declare function readFunctionDirectoryRosterGroups(manifest: unknown): string[];
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.directoryRosterPageSchema = exports.directoryRosterQuerySchema = exports.functionDirectoryRostersSchema = exports.FUNCTION_DIRECTORY_ROSTER_PATH = void 0;
4
+ exports.readFunctionDirectoryRosterGroups = readFunctionDirectoryRosterGroups;
5
+ const zod_1 = require("zod");
6
+ const directory_config_1 = require("./directory-config");
7
+ const directory_contract_1 = require("./directory-contract");
8
+ exports.FUNCTION_DIRECTORY_ROSTER_PATH = '/api/managed-functions/directory/roster';
9
+ exports.functionDirectoryRostersSchema = zod_1.z.array(directory_config_1.directoryGroupIdSchema).min(1).max(16)
10
+ .refine(groups => new Set(groups).size === groups.length, 'Roster groups must be distinct');
11
+ exports.directoryRosterQuerySchema = zod_1.z.object({
12
+ tenant: directory_contract_1.directoryTenantSchema,
13
+ groupId: directory_config_1.directoryGroupIdSchema,
14
+ limit: zod_1.z.number().int().min(1).max(50).default(50),
15
+ cursor: zod_1.z.string().max(2048).optional(),
16
+ }).strict();
17
+ exports.directoryRosterPageSchema = zod_1.z.object({
18
+ members: zod_1.z.array(zod_1.z.object({ id: zod_1.z.string(), sub: zod_1.z.string(), name: zod_1.z.string(), email: zod_1.z.string(), deactivated: zod_1.z.literal(false) }).strict()).max(50),
19
+ nextCursor: zod_1.z.string().nullable(),
20
+ }).strict();
21
+ function readFunctionDirectoryRosterGroups(manifest) {
22
+ const parsed = zod_1.z.object({ capabilities: zod_1.z.object({ directory: zod_1.z.object({ rosters: exports.functionDirectoryRostersSchema.optional() }).optional() }).optional() }).safeParse(manifest);
23
+ return parsed.success ? parsed.data.capabilities?.directory?.rosters ?? [] : [];
24
+ }
package/dist/index.d.ts CHANGED
@@ -36,7 +36,7 @@ export type { MonitoringDeltaEvent, MonitoringPublish, MonitoringDeliveryKey, Mo
36
36
  export type { MonitoringCatalogQuery, MonitoringBucketCatalog } from './monitoring-contract';
37
37
  export type { FunctionMonitoringAnnotation, MonitoringJson } from './monitoring-annotations';
38
38
  export type { FunctionServiceMonitoringClient, FunctionServiceMonitoringOptions } from './monitoring';
39
- export type { FunctionServiceProcessesClient, FunctionServiceProcessesOptions, FunctionProcessRunQuery, FunctionProcessRunSummary, FunctionProcessRunStatus, FunctionProcessRunsPage, FunctionProcessRunsPageQuery, FunctionProcessReadRequest, FunctionProcessCompletedAgentReferenceQuery, FunctionProcessCompletedAgentReference } from './processes';
39
+ export type { FunctionServiceProcessesClient, FunctionServiceProcessesOptions, FunctionProcessRunQuery, FunctionProcessRunSummary, FunctionProcessRunStatus, FunctionProcessRunsPage, FunctionProcessRunsPageQuery, FunctionProcessReadRequest, FunctionProcessCompletedAgentReferenceQuery, FunctionProcessCompletedAgentReference, FunctionProcessCompletedNode, FunctionProcessCompletedNodeQuery } from './processes';
40
40
  export { installFunctionTracing, runWithFunctionTracing } from './tracing';
41
41
  export { createFunctionStorageClient } from './storage';
42
42
  import { type CacheManager } from "./cache";
@@ -52,3 +52,6 @@ export declare function createManagedFunctionContext({ env, }?: {
52
52
  }): ManagedFunctionContext;
53
53
  export * from './directory-contract';
54
54
  export { createFunctionServiceDirectoryClient, type FunctionServiceDirectoryOptions, type FunctionServiceDirectoryClient } from './service-directory';
55
+ export * from './directory-roster-contract';
56
+ export { functionLatticeRunCreatorAccessSchema } from './lattice-provenance-contract';
57
+ export type { FunctionLatticeRunCreatorAccess } from './lattice-provenance-contract';
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.createFunctionServiceDirectoryClient = exports.readCacheConfiguration = exports.cacheManifestSchema = exports.createCacheManager = exports.CacheError = exports.createFunctionStorageClient = exports.runWithFunctionTracing = exports.installFunctionTracing = exports.functionMonitoringAnnotationSchema = exports.monitoringPublishSchema = exports.monitoringEventsSchema = exports.monitoringPayloadHash = exports.FunctionMonitoringError = exports.createFunctionServiceMonitoringClient = exports.functionSourceJobAdmissionSchema = exports.functionAgentSourceExecutionSchema = exports.functionAgentConversationEvidenceRequestSchema = exports.functionAgentConversationEvidenceCaptureSchema = exports.functionAgentConversationEvidenceResponseSchema = exports.functionAgentSourceEvidenceCaptureSchema = exports.functionAgentSourceEvidenceRequestSchema = exports.functionAgentSourceResponseSchema = exports.createFunctionWorkflowEvidenceClient = exports.createFunctionServiceWorkflowsClient = exports.createFunctionAgentEvidenceClient = exports.FunctionAgentReadError = exports.createFunctionServiceAgentsClient = exports.FunctionProcessReadError = exports.createFunctionServiceProcessesClient = exports.functionLatticeHumanCompletionsPageSchema = exports.functionLatticeHumanCompletionsQuerySchema = exports.functionLatticeHumanCompletionSchema = exports.functionLatticeHumanCompletionQuerySchema = exports.functionLatticeExecutionContextSchema = exports.functionLatticeContextRequestSchema = exports.FunctionLatticeContextError = exports.FUNCTION_LATTICE_EXECUTION_TOKEN_HEADER = exports.FUNCTION_LATTICE_CONTEXT_PATH = exports.createFunctionInvocationClient = exports.functionLatticeStartProvenanceSchema = exports.functionLatticeParallelSnapshotQuerySchema = exports.functionLatticeParallelSnapshotSchema = exports.createFunctionLatticeClient = exports.readFunctionLatticeContextCapability = exports.functionLatticeContextCapabilitySchema = exports.FunctionDirectoryReadError = exports.createFunctionDirectoryClient = void 0;
17
+ exports.functionLatticeRunCreatorAccessSchema = exports.createFunctionServiceDirectoryClient = exports.readCacheConfiguration = exports.cacheManifestSchema = exports.createCacheManager = exports.CacheError = exports.createFunctionStorageClient = exports.runWithFunctionTracing = exports.installFunctionTracing = exports.functionMonitoringAnnotationSchema = exports.monitoringPublishSchema = exports.monitoringEventsSchema = exports.monitoringPayloadHash = exports.FunctionMonitoringError = exports.createFunctionServiceMonitoringClient = exports.functionSourceJobAdmissionSchema = exports.functionAgentSourceExecutionSchema = exports.functionAgentConversationEvidenceRequestSchema = exports.functionAgentConversationEvidenceCaptureSchema = exports.functionAgentConversationEvidenceResponseSchema = exports.functionAgentSourceEvidenceCaptureSchema = exports.functionAgentSourceEvidenceRequestSchema = exports.functionAgentSourceResponseSchema = exports.createFunctionWorkflowEvidenceClient = exports.createFunctionServiceWorkflowsClient = exports.createFunctionAgentEvidenceClient = exports.FunctionAgentReadError = exports.createFunctionServiceAgentsClient = exports.FunctionProcessReadError = exports.createFunctionServiceProcessesClient = exports.functionLatticeHumanCompletionsPageSchema = exports.functionLatticeHumanCompletionsQuerySchema = exports.functionLatticeHumanCompletionSchema = exports.functionLatticeHumanCompletionQuerySchema = exports.functionLatticeExecutionContextSchema = exports.functionLatticeContextRequestSchema = exports.FunctionLatticeContextError = exports.FUNCTION_LATTICE_EXECUTION_TOKEN_HEADER = exports.FUNCTION_LATTICE_CONTEXT_PATH = exports.createFunctionInvocationClient = exports.functionLatticeStartProvenanceSchema = exports.functionLatticeParallelSnapshotQuerySchema = exports.functionLatticeParallelSnapshotSchema = exports.createFunctionLatticeClient = exports.readFunctionLatticeContextCapability = exports.functionLatticeContextCapabilitySchema = exports.FunctionDirectoryReadError = exports.createFunctionDirectoryClient = void 0;
18
18
  exports.createManagedFunctionContext = createManagedFunctionContext;
19
19
  var directory_1 = require("./directory");
20
20
  Object.defineProperty(exports, "createFunctionDirectoryClient", { enumerable: true, get: function () { return directory_1.createFunctionDirectoryClient; } });
@@ -139,3 +139,6 @@ function lazyValkeyStore(connection, local) {
139
139
  __exportStar(require("./directory-contract"), exports);
140
140
  var service_directory_1 = require("./service-directory");
141
141
  Object.defineProperty(exports, "createFunctionServiceDirectoryClient", { enumerable: true, get: function () { return service_directory_1.createFunctionServiceDirectoryClient; } });
142
+ __exportStar(require("./directory-roster-contract"), exports);
143
+ var lattice_provenance_contract_5 = require("./lattice-provenance-contract");
144
+ Object.defineProperty(exports, "functionLatticeRunCreatorAccessSchema", { enumerable: true, get: function () { return lattice_provenance_contract_5.functionLatticeRunCreatorAccessSchema; } });
@@ -3,11 +3,14 @@ export declare const FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = "x-sequence-inv
3
3
  export declare const FUNCTION_INVOCATION_CONTEXT_PATH = "/api/managed-functions/invocation/context";
4
4
  export declare const functionInvocationIdentityCapabilitySchema: z.ZodObject<{
5
5
  identity: z.ZodLiteral<true>;
6
+ caller_capabilities: z.ZodOptional<z.ZodLiteral<true>>;
6
7
  }, z.core.$strict>;
7
8
  export declare function readFunctionInvocationIdentityCapability(manifest: unknown): boolean;
8
- export declare const functionInvocationContextRequestSchema: z.ZodObject<{
9
+ export declare const functionInvocationContextRequestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
9
10
  operation: z.ZodLiteral<"getInvocationContext">;
10
- }, z.core.$strict>;
11
+ }, z.core.$strict>, z.ZodObject<{
12
+ operation: z.ZodLiteral<"getCallerCapabilities">;
13
+ }, z.core.$strict>], "operation">;
11
14
  export type FunctionInvocationContextRequest = z.infer<typeof functionInvocationContextRequestSchema>;
12
15
  export declare const functionInvocationContextSchema: z.ZodObject<{
13
16
  receiver: z.ZodObject<{
@@ -34,3 +37,23 @@ export declare class FunctionInvocationContextError extends Error {
34
37
  readonly name = "FunctionInvocationContextError";
35
38
  constructor(status: number, code: string, message: string);
36
39
  }
40
+ export declare const functionInvocationCapabilitiesSchema: z.ZodObject<{
41
+ receiver: z.ZodObject<{
42
+ functionId: z.ZodString;
43
+ versionId: z.ZodString;
44
+ invocationId: z.ZodString;
45
+ orgId: z.ZodString;
46
+ serviceAccountId: z.ZodString;
47
+ serviceAccountSub: z.ZodString;
48
+ }, z.core.$strict>;
49
+ caller: z.ZodObject<{
50
+ kind: z.ZodEnum<{
51
+ human: "human";
52
+ service_account: "service_account";
53
+ system: "system";
54
+ }>;
55
+ sub: z.ZodString;
56
+ }, z.core.$strict>;
57
+ capabilities: z.ZodArray<z.ZodString>;
58
+ }, z.core.$strict>;
59
+ export type FunctionInvocationCapabilities = z.infer<typeof functionInvocationCapabilitiesSchema>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FunctionInvocationContextError = exports.functionInvocationContextSchema = exports.functionInvocationContextRequestSchema = exports.functionInvocationIdentityCapabilitySchema = exports.FUNCTION_INVOCATION_CONTEXT_PATH = exports.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = void 0;
3
+ exports.functionInvocationCapabilitiesSchema = exports.FunctionInvocationContextError = exports.functionInvocationContextSchema = exports.functionInvocationContextRequestSchema = exports.functionInvocationIdentityCapabilitySchema = exports.FUNCTION_INVOCATION_CONTEXT_PATH = exports.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = void 0;
4
4
  exports.readFunctionInvocationIdentityCapability = readFunctionInvocationIdentityCapability;
5
5
  const zod_1 = require("zod");
6
6
  exports.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER = 'x-sequence-invocation-identity-token';
@@ -9,6 +9,7 @@ const identifier = zod_1.z.string().min(1).max(255);
9
9
  const principal = zod_1.z.string().min(1).max(512);
10
10
  exports.functionInvocationIdentityCapabilitySchema = zod_1.z.strictObject({
11
11
  identity: zod_1.z.literal(true),
12
+ caller_capabilities: zod_1.z.literal(true).optional(),
12
13
  });
13
14
  function readFunctionInvocationIdentityCapability(manifest) {
14
15
  if (typeof manifest !== 'object' || manifest === null)
@@ -18,18 +19,21 @@ function readFunctionInvocationIdentityCapability(manifest) {
18
19
  return false;
19
20
  return exports.functionInvocationIdentityCapabilitySchema.safeParse(Reflect.get(capabilities, 'invocation')).success;
20
21
  }
21
- exports.functionInvocationContextRequestSchema = zod_1.z.strictObject({
22
- operation: zod_1.z.literal('getInvocationContext'),
23
- });
22
+ exports.functionInvocationContextRequestSchema = zod_1.z.discriminatedUnion('operation', [
23
+ zod_1.z.strictObject({ operation: zod_1.z.literal('getInvocationContext') }),
24
+ zod_1.z.strictObject({ operation: zod_1.z.literal('getCallerCapabilities') }),
25
+ ]);
24
26
  exports.functionInvocationContextSchema = zod_1.z.strictObject({
25
- receiver: zod_1.z.strictObject({
27
+ receiver: zod_1.z
28
+ .strictObject({
26
29
  functionId: identifier,
27
30
  versionId: identifier,
28
31
  invocationId: identifier,
29
32
  orgId: identifier,
30
33
  serviceAccountId: identifier,
31
34
  serviceAccountSub: principal,
32
- }).refine((value) => value.serviceAccountSub === `service-account|${value.serviceAccountId}`, 'The receiver subject must identify the attached service account'),
35
+ })
36
+ .refine((value) => value.serviceAccountSub === `service-account|${value.serviceAccountId}`, 'The receiver subject must identify the attached service account'),
33
37
  caller: zod_1.z.strictObject({
34
38
  kind: zod_1.z.enum(['human', 'service_account', 'system']),
35
39
  sub: principal,
@@ -46,3 +50,14 @@ class FunctionInvocationContextError extends Error {
46
50
  }
47
51
  }
48
52
  exports.FunctionInvocationContextError = FunctionInvocationContextError;
53
+ exports.functionInvocationCapabilitiesSchema = exports.functionInvocationContextSchema
54
+ .extend({
55
+ capabilities: zod_1.z
56
+ .array(zod_1.z
57
+ .string()
58
+ .min(1)
59
+ .max(140)
60
+ .regex(/^[a-z0-9][a-z0-9/_.:-]*$/))
61
+ .max(256),
62
+ })
63
+ .refine((value) => new Set(value.capabilities).size === value.capabilities.length, 'Capabilities must be unique');
@@ -1,8 +1,9 @@
1
- import { type FunctionInvocationContext } from './invocation-contract';
1
+ import { type FunctionInvocationCapabilities, type FunctionInvocationContext } from './invocation-contract';
2
2
  export * from './invocation-contract';
3
3
  import type { FunctionInvocationClientOptions } from './invocation-client';
4
4
  export type { FunctionInvocationClientOptions } from './invocation-client';
5
5
  export interface FunctionInvocationClient {
6
6
  getInvocationContext(): Promise<FunctionInvocationContext>;
7
+ getCallerCapabilities(): Promise<FunctionInvocationCapabilities>;
7
8
  }
8
9
  export declare function createFunctionInvocationClient({ request, baseUrl, fetchImpl, }: FunctionInvocationClientOptions): FunctionInvocationClient;
@@ -34,7 +34,11 @@ const tokenClaimsSchema = zod_1.z.strictObject({
34
34
  exp: zod_1.z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
35
35
  });
36
36
  const errorSchema = zod_1.z.strictObject({
37
- code: zod_1.z.string().min(1).max(128).regex(/^[a-z][a-z0-9_]*$/),
37
+ code: zod_1.z
38
+ .string()
39
+ .min(1)
40
+ .max(128)
41
+ .regex(/^[a-z][a-z0-9_]*$/),
38
42
  detail: zod_1.z.string().min(1).max(2000),
39
43
  });
40
44
  const invalidContext = () => new invocation_contract_1.FunctionInvocationContextError(401, 'invalid_context', 'This invocation has no valid identity credential');
@@ -75,10 +79,13 @@ function trustedOrigin(baseUrl) {
75
79
  catch {
76
80
  throw invalid();
77
81
  }
78
- const loopback = url.protocol === 'http:' &&
79
- ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
80
- if ((!loopback && url.protocol !== 'https:') || url.username || url.password ||
81
- url.pathname !== '/' || url.search || url.hash)
82
+ const loopback = url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
83
+ if ((!loopback && url.protocol !== 'https:') ||
84
+ url.username ||
85
+ url.password ||
86
+ url.pathname !== '/' ||
87
+ url.search ||
88
+ url.hash)
82
89
  throw invalid();
83
90
  return url.origin;
84
91
  }
@@ -88,47 +95,50 @@ function requireFresh(claims) {
88
95
  }
89
96
  function matchesInvocation({ context, claims, }) {
90
97
  const { receiver, caller } = context;
91
- return receiver.functionId === claims.functionId &&
98
+ return (receiver.functionId === claims.functionId &&
92
99
  receiver.versionId === claims.versionId &&
93
100
  receiver.invocationId === claims.invocationId &&
94
101
  receiver.orgId === claims.org &&
95
102
  receiver.serviceAccountId === claims.serviceAccountId &&
96
- caller.kind === claims.callerKind && caller.sub === claims.callerSub;
103
+ caller.kind === claims.callerKind &&
104
+ caller.sub === claims.callerSub);
97
105
  }
98
106
  function createFunctionInvocationClient({ request, baseUrl, fetchImpl = globalThis.fetch, }) {
99
107
  const url = `${trustedOrigin(baseUrl)}${invocation_contract_1.FUNCTION_INVOCATION_CONTEXT_PATH}`;
100
108
  const { token, claims } = readCredential({ request });
109
+ async function read(operation, schema) {
110
+ requireFresh(claims);
111
+ let response;
112
+ try {
113
+ response = await fetchImpl(url, {
114
+ method: 'POST',
115
+ headers: {
116
+ 'content-type': 'application/json',
117
+ [invocation_contract_1.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER]: token,
118
+ },
119
+ body: JSON.stringify(invocation_contract_1.functionInvocationContextRequestSchema.parse({ operation })),
120
+ redirect: 'error',
121
+ signal: AbortSignal.timeout(30_000),
122
+ });
123
+ }
124
+ catch {
125
+ throw new invocation_contract_1.FunctionInvocationContextError(502, 'context_request_failed', 'The invocation context request failed');
126
+ }
127
+ if (response.redirected || (response.status >= 300 && response.status < 400))
128
+ throw new invocation_contract_1.FunctionInvocationContextError(502, 'redirect_refused', 'The invocation context request must not redirect');
129
+ const result = await response.json().catch(() => null);
130
+ if (!response.ok) {
131
+ const error = errorSchema.safeParse(result);
132
+ throw new invocation_contract_1.FunctionInvocationContextError(response.status, error.success ? error.data.code : 'context_read_failed', error.success && !error.data.detail.includes(token) ? error.data.detail : 'Invocation context read failed');
133
+ }
134
+ requireFresh(claims);
135
+ const parsed = schema.safeParse(result);
136
+ if (!parsed.success || !matchesInvocation({ context: parsed.data, claims }))
137
+ throw new invocation_contract_1.FunctionInvocationContextError(502, 'malformed_response', 'Atlas returned an invalid invocation context response');
138
+ return parsed.data;
139
+ }
101
140
  return {
102
- async getInvocationContext() {
103
- requireFresh(claims);
104
- let response;
105
- try {
106
- response = await fetchImpl(url, {
107
- method: 'POST',
108
- headers: {
109
- 'content-type': 'application/json',
110
- [invocation_contract_1.FUNCTION_INVOCATION_IDENTITY_TOKEN_HEADER]: token,
111
- },
112
- body: JSON.stringify(invocation_contract_1.functionInvocationContextRequestSchema.parse({ operation: 'getInvocationContext' })),
113
- redirect: 'error', signal: AbortSignal.timeout(30_000),
114
- });
115
- }
116
- catch {
117
- throw new invocation_contract_1.FunctionInvocationContextError(502, 'context_request_failed', 'The invocation context request failed');
118
- }
119
- if (response.redirected || (response.status >= 300 && response.status < 400))
120
- throw new invocation_contract_1.FunctionInvocationContextError(502, 'redirect_refused', 'The invocation context request must not redirect');
121
- const result = await response.json().catch(() => null);
122
- if (!response.ok) {
123
- const error = errorSchema.safeParse(result);
124
- throw new invocation_contract_1.FunctionInvocationContextError(response.status, error.success ? error.data.code : 'context_read_failed', error.success && !error.data.detail.includes(token)
125
- ? error.data.detail : 'Invocation context read failed');
126
- }
127
- requireFresh(claims);
128
- const parsed = invocation_contract_1.functionInvocationContextSchema.safeParse(result);
129
- if (!parsed.success || !matchesInvocation({ context: parsed.data, claims }))
130
- throw new invocation_contract_1.FunctionInvocationContextError(502, 'malformed_response', 'Atlas returned an invalid invocation context response');
131
- return parsed.data;
132
- },
141
+ getInvocationContext: () => read('getInvocationContext', invocation_contract_1.functionInvocationContextSchema),
142
+ getCallerCapabilities: () => read('getCallerCapabilities', invocation_contract_1.functionInvocationCapabilitiesSchema),
133
143
  };
134
144
  }