@north-light/api 0.3.454 → 0.3.456

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.
@@ -1,5 +1,5 @@
1
1
  /** The contract level this build serves and requires. Written by `scripts/contract.mjs release`; never edit by hand. */
2
- export declare const CONTRACT_LEVEL = "1.3";
2
+ export declare const CONTRACT_LEVEL = "1.4";
3
3
  /** Request header naming the one contract level the caller needs, e.g. `1.3`. Optional: absent means no check. */
4
4
  export declare const REQUIRED_CONTRACT_HEADER = "Crouter-Required-Contract";
5
5
  /** Response header listing the contract levels the server serves, comma-separated, one per major, e.g. `1.3`. */
@@ -12,7 +12,7 @@
12
12
  //
13
13
  // PURITY (spec §3.1): Node built-ins + `src/api/*` only.
14
14
  /** The contract level this build serves and requires. Written by `scripts/contract.mjs release`; never edit by hand. */
15
- export const CONTRACT_LEVEL = '1.3';
15
+ export const CONTRACT_LEVEL = '1.4';
16
16
  /** Request header naming the one contract level the caller needs, e.g. `1.3`. Optional: absent means no check. */
17
17
  export const REQUIRED_CONTRACT_HEADER = 'Crouter-Required-Contract';
18
18
  /** Response header listing the contract levels the server serves, comma-separated, one per major, e.g. `1.3`. */
@@ -134,6 +134,31 @@ export declare const errorCodes: {
134
134
  readonly status: 409;
135
135
  readonly retryable: false;
136
136
  };
137
+ readonly invalid_argument: {
138
+ readonly type: "invalid_request_error";
139
+ readonly status: 400;
140
+ readonly retryable: false;
141
+ };
142
+ readonly machine_required: {
143
+ readonly type: "invalid_request_error";
144
+ readonly status: 409;
145
+ readonly retryable: false;
146
+ };
147
+ readonly device_offline: {
148
+ readonly type: "server_error";
149
+ readonly status: 503;
150
+ readonly retryable: true;
151
+ };
152
+ readonly device_timeout: {
153
+ readonly type: "server_error";
154
+ readonly status: 504;
155
+ readonly retryable: true;
156
+ };
157
+ readonly device_disconnected: {
158
+ readonly type: "server_error";
159
+ readonly status: 503;
160
+ readonly retryable: false;
161
+ };
137
162
  readonly not_found: {
138
163
  readonly type: "invalid_request_error";
139
164
  readonly status: 404;
@@ -37,6 +37,16 @@ export const errorCodes = {
37
37
  // A peer machine runs a crtr release below the peer-protocol floor; details `{ peer_version, floor, receiver_version }`. Update it with `crtr sys update`.
38
38
  peer_version_too_old: { type: 'invalid_request_error', status: 426, retryable: false },
39
39
  conflict: { type: 'invalid_request_error', status: 409, retryable: false },
40
+ // `provider.call` input that cannot apply: `machine` on a provider that is not served by a machine.
41
+ invalid_argument: { type: 'invalid_request_error', status: 400, retryable: false },
42
+ // A device call names no machine and the account has several (or the named one is not a device); details `{ candidates: [{ machine_id, name, last_seen }] }`.
43
+ machine_required: { type: 'invalid_request_error', status: 409, retryable: false },
44
+ // The device machine is offline, unreachable, or its Desktop is signed out.
45
+ device_offline: { type: 'server_error', status: 503, retryable: true },
46
+ // The device did not answer within the call's deadline.
47
+ device_timeout: { type: 'server_error', status: 504, retryable: true },
48
+ // The device's relay connection dropped mid-call; the action may have run, so it is not retryable.
49
+ device_disconnected: { type: 'server_error', status: 503, retryable: false },
40
50
  not_found: { type: 'invalid_request_error', status: 404, retryable: false },
41
51
  model_unavailable: { type: 'invalid_request_error', status: 404, retryable: false },
42
52
  upstream_model_unavailable: { type: 'server_error', status: 503, retryable: true },
@@ -1,5 +1,6 @@
1
1
  import { type ValidatedCommandManifest } from '../../api/command-manifest/manifest.js';
2
2
  import type { KindConfig, MemoryExtensionDeclarations, PageComponentRegistration, PluginBundle, PluginManifest, Scope } from '../../types.js';
3
+ import { type BundleTransport } from './endpoint.js';
3
4
  /** Who may call a capability provider's tool group (contract 3). */
4
5
  export type ProviderGroupWho = 'own' | 'user' | 'allowlist' | 'any';
5
6
  /** One tool group a capability provider declares in `bundle.json`. */
@@ -34,11 +35,7 @@ export interface ValidatedBundle {
34
35
  version?: number;
35
36
  /** The transport `bundle.json` declares, when it declares one (a bundle the
36
37
  * directory emits for a capability provider always does). */
37
- transport?: {
38
- kind: 'http';
39
- endpoint: string;
40
- authEnv?: string;
41
- };
38
+ transport?: BundleTransport;
42
39
  /** The capability-provider block: present only on a provider bundle. */
43
40
  provider?: ProviderBlock;
44
41
  /** Kind-registry contributions declared in `bundle.json` (optional). The
@@ -82,11 +79,7 @@ export declare function validatePluginBundle(archive: Uint8Array, options: {
82
79
  extensibleCoreBranches?: ReadonlySet<string>;
83
80
  }): Promise<PluginBundleValidation>;
84
81
  /** An archive install's invocation transport. */
85
- export type BundleInvocationTransport = {
86
- kind: 'http';
87
- endpoint: string;
88
- authEnv?: string;
89
- };
82
+ export type BundleInvocationTransport = BundleTransport;
90
83
  /** The hash recorded as a bundle package's `version`: the exact archive bytes
91
84
  * unpacked at its root. Same bytes, same version — which is what lets a
92
85
  * re-sent archive be recognized as the generation already installed. */
@@ -8,7 +8,7 @@ import { general } from '../errors.js';
8
8
  import { atomicWriteJson, atomicWriteText, ensureDir, nowIso, pathExists, removePath, syncDirectory, syncTree } from '../fs-utils.js';
9
9
  import { invalidPageComponentsReasons, normalizePageComponents } from '../human/page-catalog.js';
10
10
  import { validateMemoryExtensionDeclarations } from '../plugin-extensions.js';
11
- import { validateHttpPluginTransport } from './endpoint.js';
11
+ import { validateBundleTransport } from './endpoint.js';
12
12
  /** A capability provider id or tool group id: contract 1's `<id>` grammar. */
13
13
  const PROVIDER_ID = /^[A-Za-z0-9_-]{1,64}$/;
14
14
  const PROVIDER_KEYS = new Set(['id', 'major', 'groups']);
@@ -240,7 +240,7 @@ function providerBundleIssue(metadata, commands) {
240
240
  if (metadata.transport === undefined) {
241
241
  return bundleInvalid('a provider bundle must declare its transport', '(missing)', 'transport { kind: "http", endpoint } in bundle.json', 'Add the provider endpoint as bundle.json transport.', 'bundle.json.transport');
242
242
  }
243
- if (metadata.transport.authEnv !== undefined) {
243
+ if (metadata.transport.kind === 'http' && metadata.transport.authEnv !== undefined) {
244
244
  return bundleInvalid('a provider bundle must not declare authEnv', metadata.transport.authEnv, 'no authEnv: the runtime presents its own outbound token', 'Remove transport.authEnv from bundle.json.', 'bundle.json.transport.authEnv');
245
245
  }
246
246
  const declared = new Set(provider.groups.map((g) => g.group));
@@ -315,10 +315,10 @@ function parseBundleMetadata(bytes) {
315
315
  }
316
316
  let transport;
317
317
  if (record['transport'] !== undefined) {
318
- const t = validateHttpPluginTransport(record['transport']);
318
+ const t = validateBundleTransport(record['transport']);
319
319
  if (t.transport === undefined) {
320
320
  return {
321
- issue: bundleInvalid('bundle.json transport is invalid', t.errors.join('; '), '{ kind: "http", endpoint, authEnv? }', 'Fix transport in bundle.json.', 'bundle.json.transport'),
321
+ issue: bundleInvalid('bundle.json transport is invalid', t.errors.join('; '), '{ kind: "http", endpoint, authEnv? } or { kind: "machine" }', 'Fix transport in bundle.json.', 'bundle.json.transport'),
322
322
  };
323
323
  }
324
324
  transport = t.transport;
@@ -22,3 +22,15 @@ export declare function validateHttpPluginTransport(raw: unknown): {
22
22
  };
23
23
  errors: string[];
24
24
  };
25
+ /** The transport a served provider bundle declares: HTTP (the provider's endpoint) or `{ kind: "machine" }` (calls go to a device machine). */
26
+ export type BundleTransport = {
27
+ kind: 'http';
28
+ endpoint: string;
29
+ authEnv?: string;
30
+ } | {
31
+ kind: 'machine';
32
+ };
33
+ export declare function validateBundleTransport(raw: unknown): {
34
+ transport?: BundleTransport;
35
+ errors: string[];
36
+ };
@@ -49,3 +49,10 @@ export function validateHttpPluginTransport(raw) {
49
49
  errors.push(...validateEnvVarName(transport.authEnv).errors);
50
50
  return errors.length ? { errors } : { transport: { kind: 'http', endpoint: normalizeEndpoint(transport.endpoint), ...(transport.authEnv !== undefined ? { authEnv: transport.authEnv } : {}) }, errors };
51
51
  }
52
+ export function validateBundleTransport(raw) {
53
+ if (typeof raw === 'object' && raw !== null && !Array.isArray(raw) && raw.kind === 'machine') {
54
+ const unknown = Object.keys(raw).filter((key) => key !== 'kind');
55
+ return unknown.length ? { errors: [`transport has unknown keys: ${unknown.join(', ')}`] } : { transport: { kind: 'machine' }, errors: [] };
56
+ }
57
+ return validateHttpPluginTransport(raw);
58
+ }
package/dist/types.d.ts CHANGED
@@ -23,6 +23,10 @@ export type PluginTransport = {
23
23
  kind: 'http';
24
24
  endpoint: string;
25
25
  authEnv?: string;
26
+ }
27
+ /** A provider whose calls go to one of the account's `kind = device` machines over the relay; there is no endpoint. */
28
+ | {
29
+ kind: 'machine';
26
30
  };
27
31
  /** Provenance for a crouter-materialized HTTP plugin directory archive. */
28
32
  export interface PluginBundle {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/api",
3
- "version": "0.3.454",
3
+ "version": "0.3.456",
4
4
  "description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, the CrtrClient, and the command-plugin manifest format. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/api/index.js",