@nsp-labs/agnostic-sdk 1.0.4 → 1.1.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/CHANGELOG.md CHANGED
@@ -9,6 +9,24 @@ and pass the runtime OpenAPI schema check.
9
9
 
10
10
  ## Unreleased
11
11
 
12
+ ## 1.1.0 - 2026-07-26
13
+
14
+ ### Added
15
+
16
+ - Added an exact public-surface drift guard and a deterministic manifest
17
+ fingerprint so Agent codegen can re-read the installed SDK contract on every
18
+ generation step instead of relying on a copied namespace list.
19
+ - Added `auth.getSession()` for optional App Auth sessions and
20
+ `auth.requireScopes()` for application-level scope guardrails after session
21
+ verification.
22
+
23
+ ### Changed
24
+
25
+ - Runtime SDK manifest consumers can now derive scaffold versions, Agent review
26
+ allowlists, and source-write deny rules from the exported package contract.
27
+ The runtime OpenAPI schema is unchanged; the callable SDK surface adds only
28
+ the backwards-compatible App Auth helpers listed above.
29
+
12
30
  ## 1.0.4 - 2026-06-18
13
31
 
14
32
  ### Changed
package/README.md CHANGED
@@ -46,13 +46,33 @@ the incoming App Auth session through the runtime helper:
46
46
  ```ts
47
47
  const session = await agnostic.auth.requireSession(request);
48
48
 
49
- await agnostic.data.table('orders').records.update(
50
- 'order_123',
51
- { values: { status: 'fulfilled' } },
52
- { actor: session.actor },
53
- );
49
+ await agnostic.data
50
+ .table('orders')
51
+ .records.update(
52
+ 'order_123',
53
+ { values: { status: 'fulfilled' } },
54
+ { actor: session.actor },
55
+ );
56
+ ```
57
+
58
+ Use `getSession(request)` for routes that support both guests and signed-in
59
+ users. It returns `null` when the request has no App Auth session:
60
+
61
+ ```ts
62
+ const session = await agnostic.auth.getSession(request);
54
63
  ```
55
64
 
65
+ Use `requireScopes(request, scopes)` for application-level scope guardrails.
66
+ This verifies the session first and throws `app_auth_scope_missing` when one of
67
+ the required app-user scopes is absent:
68
+
69
+ ```ts
70
+ const session = await agnostic.auth.requireScopes(request, ['orders:write']);
71
+ ```
72
+
73
+ Scope checks do not replace ownership or other business rules in the
74
+ application backend.
75
+
56
76
  The helper extracts `Authorization: Bearer <app-session>` or an
57
77
  `agnostic_app_session_*` cookie, then calls
58
78
  `/api/v1/runtime/app-auth/session/verify` with the server-side runtime token.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nsp-labs/agnostic-sdk",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "Server-side Runtime SDK for Agnostic project services, workers, automations, and trusted local scripts.",
5
5
  "license": "ISC",
6
6
  "type": "commonjs",
package/src/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { AgnosticRuntime, RuntimeAppAuthNamespace, RuntimeContextNamespace, RuntimeDataNamespace, RuntimeDataRecordsClient, RuntimeDataTableClient, RuntimeDataViewClient, RuntimeDataViewTableClient, RuntimeWorkflowRunsNamespace, RuntimeWorkflowsNamespace, createAgnosticRuntime, } from './lib/runtime-client';
2
2
  export { normalizeApiUrl, resolveRuntimeContext } from './lib/context';
3
3
  export { AgnosticRuntimeError } from './lib/errors';
4
+ export { AGNOSTIC_RUNTIME_SDK_MANIFEST, type AgnosticRuntimeSdkManifest, } from './lib/manifest';
4
5
  export type { AgnosticRuntimeConfig, ResolvedRuntimeContext, RuntimeActorMetadata, RuntimeActorType, RuntimeAppAuthActor, RuntimeAppAuthCachePolicy, RuntimeAppAuthRequestLike, RuntimeAppAuthSession, RuntimeAppAuthSessionClaims, RuntimeAppAuthUserClaims, RuntimeAppAuthUserResult, RuntimeCreateRecordInput, RuntimeDataField, RuntimeDataViewState, RuntimeIdentityContext, RuntimeListRecordsOptions, RuntimeListWindowOptions, RuntimeRecord, RuntimeRecordMutation, RuntimeRecordsList, RuntimeRequestOptions, RuntimeRowData, RuntimeRowValue, RuntimeTableWindow, RuntimeUpdateRecordInput, RuntimeWorkflowRun, RuntimeWorkflowStepRun, RuntimeWorkflowWaitOptions, WorkflowRunStatus, } from './lib/types';
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AgnosticRuntimeError = exports.resolveRuntimeContext = exports.normalizeApiUrl = exports.createAgnosticRuntime = exports.RuntimeWorkflowsNamespace = exports.RuntimeWorkflowRunsNamespace = exports.RuntimeDataViewTableClient = exports.RuntimeDataViewClient = exports.RuntimeDataTableClient = exports.RuntimeDataRecordsClient = exports.RuntimeDataNamespace = exports.RuntimeContextNamespace = exports.RuntimeAppAuthNamespace = exports.AgnosticRuntime = void 0;
3
+ exports.AGNOSTIC_RUNTIME_SDK_MANIFEST = exports.AgnosticRuntimeError = exports.resolveRuntimeContext = exports.normalizeApiUrl = exports.createAgnosticRuntime = exports.RuntimeWorkflowsNamespace = exports.RuntimeWorkflowRunsNamespace = exports.RuntimeDataViewTableClient = exports.RuntimeDataViewClient = exports.RuntimeDataTableClient = exports.RuntimeDataRecordsClient = exports.RuntimeDataNamespace = exports.RuntimeContextNamespace = exports.RuntimeAppAuthNamespace = exports.AgnosticRuntime = void 0;
4
4
  var runtime_client_1 = require("./lib/runtime-client");
5
5
  Object.defineProperty(exports, "AgnosticRuntime", { enumerable: true, get: function () { return runtime_client_1.AgnosticRuntime; } });
6
6
  Object.defineProperty(exports, "RuntimeAppAuthNamespace", { enumerable: true, get: function () { return runtime_client_1.RuntimeAppAuthNamespace; } });
@@ -18,4 +18,6 @@ Object.defineProperty(exports, "normalizeApiUrl", { enumerable: true, get: funct
18
18
  Object.defineProperty(exports, "resolveRuntimeContext", { enumerable: true, get: function () { return context_1.resolveRuntimeContext; } });
19
19
  var errors_1 = require("./lib/errors");
20
20
  Object.defineProperty(exports, "AgnosticRuntimeError", { enumerable: true, get: function () { return errors_1.AgnosticRuntimeError; } });
21
+ var manifest_1 = require("./lib/manifest");
22
+ Object.defineProperty(exports, "AGNOSTIC_RUNTIME_SDK_MANIFEST", { enumerable: true, get: function () { return manifest_1.AGNOSTIC_RUNTIME_SDK_MANIFEST; } });
21
23
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,39 @@
1
+ export declare const AGNOSTIC_RUNTIME_SDK_MANIFEST: Readonly<{
2
+ readonly promptSync: Readonly<{
3
+ source: "sdk_exported_manifest";
4
+ strategy: "inject_on_every_agent_codegen_context";
5
+ surfaceFingerprint: string;
6
+ driftPolicy: "fail_ci_on_public_surface_or_package_version_mismatch";
7
+ memorizedSdkKnowledgeAllowed: false;
8
+ }>;
9
+ readonly schema: "agnostic_runtime_sdk_manifest.v1";
10
+ readonly package: Readonly<{
11
+ name: "@nsp-labs/agnostic-sdk";
12
+ version: "1.1.0";
13
+ factory: "createAgnosticRuntime";
14
+ runtime: "server_only";
15
+ }>;
16
+ readonly context: Readonly<{
17
+ automatic: true;
18
+ environmentVariables: readonly string[];
19
+ secretEnvironmentVariables: readonly string[];
20
+ }>;
21
+ readonly rootMembers: readonly [...("data" | "auth" | "context" | "workflows" | "workflowRuns")[], "getRuntimeContext"];
22
+ readonly clientMethods: readonly ["getRuntimeContext"];
23
+ readonly namespaces: Readonly<{
24
+ auth: readonly ("requireSession" | "getSession" | "requireScopes" | "getUser")[];
25
+ context: readonly "get"[];
26
+ data: readonly ("table(name).records.delete" | "table(name).records.list" | "table(name).records.create" | "table(name).records.update" | "view(id).table.window")[];
27
+ workflows: readonly ("start" | "getRun")[];
28
+ workflowRuns: readonly ("get" | "wait" | "listSteps")[];
29
+ }>;
30
+ readonly unsupportedNamespaces: readonly string[];
31
+ readonly boundaries: Readonly<{
32
+ controlPlaneProvisioning: "agent_product_tools";
33
+ runtimeAccess: "server_sdk";
34
+ browserAccess: "public_api_or_app_auth_session";
35
+ browserPackageImportAllowed: false;
36
+ browserRuntimeTokenAllowed: false;
37
+ }>;
38
+ }>;
39
+ export type AgnosticRuntimeSdkManifest = typeof AGNOSTIC_RUNTIME_SDK_MANIFEST;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AGNOSTIC_RUNTIME_SDK_MANIFEST = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const AUTH_KEYS_LITERAL = [
6
+ 'requireSession',
7
+ 'getSession',
8
+ 'requireScopes',
9
+ 'getUser',
10
+ ];
11
+ const AUTH_KEYS = AUTH_KEYS_LITERAL;
12
+ const CONTEXT_KEYS_LITERAL = ['get'];
13
+ const CONTEXT_KEYS = CONTEXT_KEYS_LITERAL;
14
+ const DATA_NAMESPACE_KEYS_LITERAL = ['table', 'view'];
15
+ const DATA_NAMESPACE_KEYS = DATA_NAMESPACE_KEYS_LITERAL;
16
+ const DATA_TABLE_KEYS_LITERAL = ['records'];
17
+ const DATA_TABLE_KEYS = DATA_TABLE_KEYS_LITERAL;
18
+ const DATA_RECORD_KEYS_LITERAL = [
19
+ 'list',
20
+ 'create',
21
+ 'update',
22
+ 'delete',
23
+ ];
24
+ const DATA_RECORD_KEYS = DATA_RECORD_KEYS_LITERAL;
25
+ const DATA_VIEW_KEYS_LITERAL = ['table'];
26
+ const DATA_VIEW_KEYS = DATA_VIEW_KEYS_LITERAL;
27
+ const DATA_VIEW_TABLE_KEYS_LITERAL = ['window'];
28
+ const DATA_VIEW_TABLE_KEYS = DATA_VIEW_TABLE_KEYS_LITERAL;
29
+ const WORKFLOW_KEYS_LITERAL = ['start', 'getRun'];
30
+ const WORKFLOW_KEYS = WORKFLOW_KEYS_LITERAL;
31
+ const WORKFLOW_RUN_KEYS_LITERAL = ['get', 'wait', 'listSteps'];
32
+ const WORKFLOW_RUN_KEYS = WORKFLOW_RUN_KEYS_LITERAL;
33
+ const CLIENT_METHODS = Object.freeze(['getRuntimeContext']);
34
+ const NAMESPACES = Object.freeze({
35
+ auth: Object.freeze([...AUTH_KEYS]),
36
+ context: Object.freeze([...CONTEXT_KEYS]),
37
+ data: Object.freeze([
38
+ ...DATA_RECORD_KEYS.map((method) => `${DATA_NAMESPACE_KEYS[0]}(name).${DATA_TABLE_KEYS[0]}.${method}`),
39
+ ...DATA_VIEW_TABLE_KEYS.map((method) => `${DATA_NAMESPACE_KEYS[1]}(id).${DATA_VIEW_KEYS[0]}.${method}`),
40
+ ]),
41
+ workflows: Object.freeze([...WORKFLOW_KEYS]),
42
+ workflowRuns: Object.freeze([...WORKFLOW_RUN_KEYS]),
43
+ });
44
+ const ROOT_MEMBERS_LITERAL = Object.freeze([
45
+ ...Object.keys(NAMESPACES),
46
+ ...CLIENT_METHODS,
47
+ ]);
48
+ const ROOT_MEMBERS = ROOT_MEMBERS_LITERAL;
49
+ const MANIFEST_CONTRACT = Object.freeze({
50
+ schema: 'agnostic_runtime_sdk_manifest.v1',
51
+ package: Object.freeze({
52
+ name: '@nsp-labs/agnostic-sdk',
53
+ version: '1.1.0',
54
+ factory: 'createAgnosticRuntime',
55
+ runtime: 'server_only',
56
+ }),
57
+ context: Object.freeze({
58
+ automatic: true,
59
+ environmentVariables: Object.freeze([
60
+ 'AGNOSTIC_API_URL',
61
+ 'AGNOSTIC_PROJECT_ID',
62
+ 'AGNOSTIC_ENVIRONMENT',
63
+ 'AGNOSTIC_RUNTIME_TOKEN',
64
+ ]),
65
+ secretEnvironmentVariables: Object.freeze(['AGNOSTIC_RUNTIME_TOKEN']),
66
+ }),
67
+ rootMembers: ROOT_MEMBERS,
68
+ clientMethods: CLIENT_METHODS,
69
+ namespaces: NAMESPACES,
70
+ unsupportedNamespaces: Object.freeze([
71
+ 'ai',
72
+ 'events',
73
+ 'gateway',
74
+ 'jobs',
75
+ 'realtime',
76
+ 'storage',
77
+ ]),
78
+ boundaries: Object.freeze({
79
+ controlPlaneProvisioning: 'agent_product_tools',
80
+ runtimeAccess: 'server_sdk',
81
+ browserAccess: 'public_api_or_app_auth_session',
82
+ browserPackageImportAllowed: false,
83
+ browserRuntimeTokenAllowed: false,
84
+ }),
85
+ });
86
+ const surfaceFingerprint = `sha256:${(0, node_crypto_1.createHash)('sha256')
87
+ .update(JSON.stringify(MANIFEST_CONTRACT))
88
+ .digest('hex')}`;
89
+ exports.AGNOSTIC_RUNTIME_SDK_MANIFEST = Object.freeze({
90
+ ...MANIFEST_CONTRACT,
91
+ promptSync: Object.freeze({
92
+ source: 'sdk_exported_manifest',
93
+ strategy: 'inject_on_every_agent_codegen_context',
94
+ surfaceFingerprint,
95
+ driftPolicy: 'fail_ci_on_public_surface_or_package_version_mismatch',
96
+ memorizedSdkKnowledgeAllowed: false,
97
+ }),
98
+ });
99
+ //# sourceMappingURL=manifest.js.map
@@ -15,6 +15,8 @@ export declare class RuntimeAppAuthNamespace {
15
15
  private readonly openapi;
16
16
  constructor(openapi: RuntimeOpenApiClient);
17
17
  requireSession(request: RuntimeAppAuthRequestLike | string, options?: RuntimeRequestOptions): Promise<RuntimeAppAuthSession>;
18
+ getSession(request: RuntimeAppAuthRequestLike | string, options?: RuntimeRequestOptions): Promise<RuntimeAppAuthSession | null>;
19
+ requireScopes(request: RuntimeAppAuthRequestLike | string, scopes: readonly string[], options?: RuntimeRequestOptions): Promise<RuntimeAppAuthSession>;
18
20
  getUser(userId: string, options?: RuntimeRequestOptions): Promise<RuntimeAppAuthUserResult>;
19
21
  }
20
22
  export declare function createAgnosticRuntime(config?: AgnosticRuntimeConfig): AgnosticRuntime;
@@ -58,11 +58,35 @@ class RuntimeAppAuthNamespace {
58
58
  },
59
59
  });
60
60
  }
61
- const result = await this.openapi.POST(APP_AUTH_VERIFY_SESSION_PATH, {
62
- body: { sessionToken },
63
- headers: (0, http_client_1.runtimeRequestHeaders)(options),
64
- });
65
- return (0, http_client_1.unwrapRuntimeResult)(result, 'Failed to verify App Auth session');
61
+ return verifyAppAuthSession(this.openapi, sessionToken, options);
62
+ }
63
+ async getSession(request, options) {
64
+ const sessionToken = typeof request === 'string'
65
+ ? normalizeSessionToken(request)
66
+ : extractAppSessionToken(request);
67
+ if (!sessionToken) {
68
+ return null;
69
+ }
70
+ return verifyAppAuthSession(this.openapi, sessionToken, options);
71
+ }
72
+ async requireScopes(request, scopes, options) {
73
+ const session = await this.requireSession(request, options);
74
+ const requiredScopes = Array.from(new Set(scopes.map((scope) => scope.trim()).filter(Boolean)));
75
+ const availableScopes = new Set(session.user.scopes);
76
+ const missingScopes = requiredScopes.filter((scope) => !availableScopes.has(scope));
77
+ if (missingScopes.length > 0) {
78
+ throw new errors_1.AgnosticRuntimeError({
79
+ status: 403,
80
+ code: 'app_auth_scope_missing',
81
+ message: 'App user is missing a required scope',
82
+ details: {
83
+ availableScopes: session.user.scopes,
84
+ missingScopes,
85
+ requiredScopes,
86
+ },
87
+ });
88
+ }
89
+ return session;
66
90
  }
67
91
  async getUser(userId, options) {
68
92
  const result = await this.openapi.GET(APP_AUTH_USER_PATH, {
@@ -78,6 +102,13 @@ exports.RuntimeAppAuthNamespace = RuntimeAppAuthNamespace;
78
102
  function createAgnosticRuntime(config = {}) {
79
103
  return new AgnosticRuntime(config);
80
104
  }
105
+ async function verifyAppAuthSession(openapi, sessionToken, options) {
106
+ const result = await openapi.POST(APP_AUTH_VERIFY_SESSION_PATH, {
107
+ body: { sessionToken },
108
+ headers: (0, http_client_1.runtimeRequestHeaders)(options),
109
+ });
110
+ return (0, http_client_1.unwrapRuntimeResult)(result, 'Failed to verify App Auth session');
111
+ }
81
112
  class RuntimeContextNamespace {
82
113
  constructor(openapi) {
83
114
  this.openapi = openapi;