@north-light/sdk 0.3.658 → 0.3.660

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/dist/client.d.ts CHANGED
@@ -74,15 +74,15 @@ export interface CrouterOptions {
74
74
  }
75
75
  /** The namespaces of `Crouter` that only the owner's own daemon serves. A person's app listener answers them `404 unknown operation`. */
76
76
  export type OwnerOnly = 'spendLimits' | 'nodes' | 'bash' | 'canvas' | 'crons' | 'structuredRequests' | 'customObjects' | 'human' | 'models' | 'system' | 'auth';
77
- /** What an app reaches on a person's runtime (the app listener): `Crouter` without the owner-daemon namespaces, `files.download`
77
+ /** What an app reaches on a person's runtime (the app listener): `Crouter` without the owner-daemon namespaces, `files.link` and `files.download`
78
78
  * only, `profiles.list` only, `customObjects` register/publish/unregister and `canvas` watch/unwatch. `Crouter` is assignable to it, so a function that takes `AppClient` takes either. */
79
79
  export type AppClient = Omit<Crouter, OwnerOnly | 'files' | 'profiles'> & {
80
80
  /** Register, publish to and unregister the custom objects the app owns (`receive` and `ack` are owner-daemon only). */
81
81
  readonly customObjects: Pick<CustomObjects, 'register' | 'publish' | 'unregister'>;
82
82
  /** Link nodes to the app's objects: `watch` and `unwatch` with `watcher` (and `watcher_machine` for a node of another machine), under `crtr:objects:link:node`. */
83
83
  readonly canvas: Pick<Canvas, 'watch' | 'unwatch'>;
84
- /** Download a file the person's runtime holds (`files.download`); the other `files` calls are owner-daemon only. */
85
- readonly files: Pick<Files, 'download'>;
84
+ /** Download a file the person's runtime holds by path (`files.download`) or an agent-handed file by its id (`files.link`); the other `files` calls are owner-daemon only. */
85
+ readonly files: Pick<Files, 'download' | 'link'>;
86
86
  /** The profiles the app may start runs with (`profiles.list`); `ensure` and `retrieve` are owner-daemon only. */
87
87
  readonly profiles: Pick<Crouter['profiles'], 'list'>;
88
88
  };
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export type { RunEvent, RunEventListener, RunEventOf, RunEventType, RunStreamEnd
8
8
  export { RunReply } from './resources/run-reply.js';
9
9
  export type { RunReplyCollectOptions, RunReplyEnding, RunReplyEvent, RunReplyResult, SentRunMessage } from './resources/run-reply.js';
10
10
  export type { AppProfile, RunActivity, RunDeleteResult, RunObject, RunParsedOutcome, RunParseOptions, RunParseParams, RunRecap, RunStartParams, RunStartResult, RunStatus, RunTrace } from './resources/runs.js';
11
- export type { FileDownloadOptions } from './resources/files.js';
11
+ export type { FileDownloadOptions, FileLink } from './resources/files.js';
12
12
  export type { Upload, UploadCreateParams } from './resources/uploads.js';
13
13
  export type { AttachmentLink } from './resources/attachments.js';
14
14
  export type { Share, ShareCreated, ShareCreateParams } from './resources/shares.js';
@@ -110,7 +110,7 @@ declare const AppCrouter: new (options: CrouterOptions) => AppClient;
110
110
  /** A runtime client on one person's stored connection (`oauth.client(userId)`): an `AppClient` that refreshes its
111
111
  * token through the `OAuth2Client`'s store, plus whose connection it is and the runtime it calls. It offers only what
112
112
  * the person's app listener serves. The owner-daemon namespaces (`nodes`, `crons`, …) are absent from its
113
- * type and throw `CrouterError` if reached anyway; `files` is `download` only, `profiles` is `list` only, `customObjects` is
113
+ * type and throw `CrouterError` if reached anyway; `files` is `download` and `link` only, `profiles` is `list` only, `customObjects` is
114
114
  * `register`, `publish` and `unregister`, and `canvas` is `watch` and `unwatch`.
115
115
  * `request` still sends any route. */
116
116
  export declare class ConnectedCrouter extends AppCrouter {
@@ -70,7 +70,7 @@ const AppCrouter = Crouter;
70
70
  /** A runtime client on one person's stored connection (`oauth.client(userId)`): an `AppClient` that refreshes its
71
71
  * token through the `OAuth2Client`'s store, plus whose connection it is and the runtime it calls. It offers only what
72
72
  * the person's app listener serves. The owner-daemon namespaces (`nodes`, `crons`, …) are absent from its
73
- * type and throw `CrouterError` if reached anyway; `files` is `download` only, `profiles` is `list` only, `customObjects` is
73
+ * type and throw `CrouterError` if reached anyway; `files` is `download` and `link` only, `profiles` is `list` only, `customObjects` is
74
74
  * `register`, `publish` and `unregister`, and `canvas` is `watch` and `unwatch`.
75
75
  * `request` still sends any route. */
76
76
  export class ConnectedCrouter extends AppCrouter {
@@ -88,7 +88,7 @@ export class ConnectedCrouter extends AppCrouter {
88
88
  } });
89
89
  }
90
90
  const { files, profiles } = this;
91
- Object.defineProperty(this, 'files', { value: { download: files.download.bind(files) } });
91
+ Object.defineProperty(this, 'files', { value: { download: files.download.bind(files), link: files.link.bind(files) } });
92
92
  Object.defineProperty(this, 'profiles', { value: { list: profiles.list } });
93
93
  const { customObjects, canvas } = this;
94
94
  Object.defineProperty(this, 'customObjects', { value: { register: customObjects.register.bind(customObjects), publish: customObjects.publish.bind(customObjects), unregister: customObjects.unregister.bind(customObjects) } });
@@ -10,6 +10,15 @@ export interface FileDownloadOptions {
10
10
  }
11
11
  /** Opens a raw download; the client supplies the bearer token and refresh. */
12
12
  export type FileDownloadOpener = (path: string, options: FileDownloadOptions) => Promise<Response>;
13
+ /** A short-lived signed download link for a file an agent handed over with `crtr push file`. */
14
+ export interface FileLink {
15
+ /** Fetch this URL (no credentials needed) before `expires_at`. */
16
+ url: string;
17
+ expires_at: string;
18
+ name: string;
19
+ media_type: string;
20
+ size: number;
21
+ }
13
22
  export declare class Files {
14
23
  private readonly request;
15
24
  private readonly openDownload?;
@@ -24,11 +33,17 @@ export declare class Files {
24
33
  limit?: number;
25
34
  } & RequestOptions): Promise<FileListDTO>;
26
35
  /**
27
- * The raw bytes of a file the caller may read (app listener only). Answers the `Response`
36
+ * The raw bytes of a file the caller may read, by path (app listener only; refused on a cloud role). Answers the `Response`
28
37
  * itself (200, or 206 for `range`) with `Content-Type`, `Content-Length`, and `Content-Range`,
29
38
  * so its body can be piped on. A non-2xx answer is thrown as `APIError` — a bad range is
30
39
  * 416 `invalid_request` with `param: 'range'` — and never returned as bytes. A body cut
31
40
  * short mid-stream means the file could not be read to the end.
32
41
  */
33
42
  download(path: string, options?: FileDownloadOptions): Promise<Response>;
43
+ /**
44
+ * A signed download link for a file an agent handed over (`crtr push file`, announced by a `file.sent` run event), by its `file_id`
45
+ * (app listener only). The link is short-lived; call again for a new one. A file of another app, another person, or a run the app may
46
+ * not read is `not_found`.
47
+ */
48
+ link(fileId: string, options?: RequestOptions): Promise<FileLink>;
34
49
  }
@@ -1,4 +1,5 @@
1
1
  import { routes, } from '@north-light/api';
2
+ import { pathSegment } from './identifiers.js';
2
3
  import { withQuery } from './request.js';
3
4
  export class Files {
4
5
  request;
@@ -20,7 +21,7 @@ export class Files {
20
21
  return this.request('GET', withQuery(routes.fileList(), { path, limit }), undefined, requestOptions);
21
22
  }
22
23
  /**
23
- * The raw bytes of a file the caller may read (app listener only). Answers the `Response`
24
+ * The raw bytes of a file the caller may read, by path (app listener only; refused on a cloud role). Answers the `Response`
24
25
  * itself (200, or 206 for `range`) with `Content-Type`, `Content-Length`, and `Content-Range`,
25
26
  * so its body can be piped on. A non-2xx answer is thrown as `APIError` — a bad range is
26
27
  * 416 `invalid_request` with `param: 'range'` — and never returned as bytes. A body cut
@@ -31,4 +32,12 @@ export class Files {
31
32
  throw new TypeError('files.download requires a Crouter client');
32
33
  return this.openDownload(path, options);
33
34
  }
35
+ /**
36
+ * A signed download link for a file an agent handed over (`crtr push file`, announced by a `file.sent` run event), by its `file_id`
37
+ * (app listener only). The link is short-lived; call again for a new one. A file of another app, another person, or a run the app may
38
+ * not read is `not_found`.
39
+ */
40
+ link(fileId, options) {
41
+ return this.request('GET', `/v1/files/${encodeURIComponent(pathSegment(fileId, 'file id'))}/link`, undefined, options);
42
+ }
34
43
  }
@@ -1,9 +1,11 @@
1
1
  import type { RequestOptions } from '../types.js';
2
2
  import type { Request } from './request.js';
3
- /** `shares.create` input. */
3
+ /** `shares.create` input: exactly one of `path` or `file_id`; none or both is a 400. */
4
4
  export interface ShareCreateParams {
5
- /** Absolute path of a file the caller may read. Without `crtr:files:share`, only files in the caller's own app space. */
6
- path: string;
5
+ /** Absolute path of a file the caller may read (refused on a cloud role). Without `crtr:files:share`, only files in the caller's own app space. */
6
+ path?: string;
7
+ /** The `file_id` of a file an agent handed over with `crtr push file` (from its `file.sent` run event). */
8
+ file_id?: string;
7
9
  /** ISO 8601 time in the future; absent or null keeps the share until it is deleted. */
8
10
  expires_at?: string | null;
9
11
  }
@@ -17,6 +19,7 @@ export interface ShareCreated {
17
19
  export interface Share {
18
20
  share_id: string;
19
21
  url: string;
22
+ /** The shared file's name. */
20
23
  source_path: string;
21
24
  created_by: string;
22
25
  created_at: string;
@@ -2,7 +2,7 @@
2
2
  name: northlight
3
3
  description: "Use when building, debugging or shipping an app that signs people in with Northlight, starts runs on their Northlight runtime, or calls Northlight providers (sms, search, integrations, context, device) with @north-light/sdk."
4
4
  metadata:
5
- sdk-version: "0.3.658"
5
+ sdk-version: "0.3.660"
6
6
  ---
7
7
 
8
8
  # Building a Northlight app
@@ -27,7 +27,7 @@ Never text a person first: Comms refuses a send to anyone who has not texted you
27
27
 
28
28
  ## First: check this skill matches the SDK
29
29
 
30
- This skill is for SDK version `0.3.658`. If the project has `node_modules/@north-light/sdk/package.json`, compare its `version` with that number. If they differ, run `npx @north-light/sdk skill` in the project, then read the rewritten `.agents/skills/northlight/SKILL.md` (or `.claude/skills/northlight/SKILL.md`) instead of this copy. It needs no account. A project that has no SDK yet starts with `npx @north-light/sdk@latest init <dir>`.
30
+ This skill is for SDK version `0.3.660`. If the project has `node_modules/@north-light/sdk/package.json`, compare its `version` with that number. If they differ, run `npx @north-light/sdk skill` in the project, then read the rewritten `.agents/skills/northlight/SKILL.md` (or `.claude/skills/northlight/SKILL.md`) instead of this copy. It needs no account. A project that has no SDK yet starts with `npx @north-light/sdk@latest init <dir>`.
31
31
 
32
32
  ## Where things run
33
33
 
package/dist/version.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** This SDK's release version. Informational only: compatibility is the contract level, not this number. */
2
- export declare const SDK_VERSION = "0.3.658";
2
+ export declare const SDK_VERSION = "0.3.660";
3
3
  /** The release sent in `Crouter-Minimum-Runtime-Version` on every request. It is frozen, so a runtime from before the
4
4
  * contract level existed (which only knows this header) refuses this SDK, while every later runtime accepts it. */
5
5
  export declare const LEGACY_FLOOR = "0.3.423";
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // SDK_VERSION is written by scripts/release-version.mjs on every release; do not edit by hand.
2
2
  /** This SDK's release version. Informational only: compatibility is the contract level, not this number. */
3
- export const SDK_VERSION = '0.3.658';
3
+ export const SDK_VERSION = '0.3.660';
4
4
  // LEGACY_FLOOR is written once by `scripts/contract.mjs release`, at the first release that carries the contract level
5
5
  // (the `0.0.0` placeholder is replaced there and never again); do not edit by hand.
6
6
  /** The release sent in `Crouter-Minimum-Runtime-Version` on every request. It is frozen, so a runtime from before the
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@north-light/sdk",
3
- "version": "0.3.658",
4
- "crouterContract": "1.52",
3
+ "version": "0.3.660",
4
+ "crouterContract": "1.53",
5
5
  "description": "Typed Node and browser client for running crouter agents through the crtrd /v1 API.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -44,9 +44,9 @@
44
44
  "prepublishOnly": "node -e \"if (process.env.npm_config_tag !== 'next') { console.error('@north-light/sdk publishes only with --tag next; scripts/promote-sdk.mjs is the only mover of latest.'); process.exit(1); }\""
45
45
  },
46
46
  "dependencies": {
47
- "@north-light/api": "0.3.658",
48
- "@north-light/identity": "0.3.658",
49
- "@north-light/plugin": "0.3.658",
47
+ "@north-light/api": "0.3.660",
48
+ "@north-light/identity": "0.3.660",
49
+ "@north-light/plugin": "0.3.660",
50
50
  "jose": "^6.2.1"
51
51
  },
52
52
  "peerDependencies": {