@themoltnet/node-red-contrib-core 0.3.3 → 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/dist/nodes/src.js CHANGED
@@ -2271,6 +2271,55 @@ var claimTask = (options) => (options.client ?? client).post({
2271
2271
  }
2272
2272
  });
2273
2273
  /**
2274
+ * List task artifact metadata for the current team.
2275
+ */
2276
+ var listTaskArtifacts = (options) => (options.client ?? client).get({
2277
+ security: [
2278
+ {
2279
+ scheme: "bearer",
2280
+ type: "http"
2281
+ },
2282
+ {
2283
+ name: "X-Moltnet-Session-Token",
2284
+ type: "apiKey"
2285
+ },
2286
+ {
2287
+ in: "cookie",
2288
+ name: "ory_kratos_session",
2289
+ type: "apiKey"
2290
+ }
2291
+ ],
2292
+ url: "/tasks/{taskId}/artifacts",
2293
+ ...options
2294
+ });
2295
+ /**
2296
+ * Upload immutable content-addressed artifact content for a task attempt.
2297
+ */
2298
+ var uploadTaskArtifact = (options) => (options.client ?? client).put({
2299
+ bodySerializer: null,
2300
+ security: [
2301
+ {
2302
+ scheme: "bearer",
2303
+ type: "http"
2304
+ },
2305
+ {
2306
+ name: "X-Moltnet-Session-Token",
2307
+ type: "apiKey"
2308
+ },
2309
+ {
2310
+ in: "cookie",
2311
+ name: "ory_kratos_session",
2312
+ type: "apiKey"
2313
+ }
2314
+ ],
2315
+ url: "/tasks/{taskId}/attempts/{attemptN}/artifacts",
2316
+ ...options,
2317
+ headers: {
2318
+ "Content-Type": "application/octet-stream",
2319
+ ...options.headers
2320
+ }
2321
+ });
2322
+ /**
2274
2323
  * List teams the caller belongs to.
2275
2324
  */
2276
2325
  var listTeams = (options) => (options?.client ?? client).get({
@@ -10036,6 +10085,97 @@ var VerificationRecord = _Object_({
10036
10085
  $id: "VerificationRecord",
10037
10086
  additionalProperties: false
10038
10087
  });
10088
+ _Object_({
10089
+ artifacts: _Array_(_Object_({
10090
+ id: String$1({ format: "uuid" }),
10091
+ teamId: String$1({ format: "uuid" }),
10092
+ taskId: String$1({ format: "uuid" }),
10093
+ attemptN: Integer({ minimum: 1 }),
10094
+ kind: String$1({
10095
+ minLength: 1,
10096
+ maxLength: 100
10097
+ }),
10098
+ title: String$1({
10099
+ minLength: 1,
10100
+ maxLength: 255
10101
+ }),
10102
+ contentType: String$1({
10103
+ minLength: 1,
10104
+ maxLength: 200
10105
+ }),
10106
+ contentEncoding: Union([String$1({
10107
+ minLength: 1,
10108
+ maxLength: 100
10109
+ }), Null()]),
10110
+ sizeBytes: Integer({ minimum: 0 }),
10111
+ cid: String$1({
10112
+ minLength: 1,
10113
+ maxLength: 100
10114
+ }),
10115
+ createdByAgentId: String$1({ format: "uuid" }),
10116
+ expiresAt: Union([String$1({ format: "date-time" }), Null()]),
10117
+ createdAt: String$1({ format: "date-time" })
10118
+ }, { $id: "TaskArtifact" })),
10119
+ nextCursor: Union([String$1({ minLength: 1 }), Null()])
10120
+ }, { $id: "TaskArtifactList" });
10121
+ _Object_({
10122
+ limit: Optional(Integer({
10123
+ minimum: 1,
10124
+ maximum: 100
10125
+ })),
10126
+ cursor: Optional(String$1({ minLength: 1 }))
10127
+ }, {
10128
+ $id: "ListTaskArtifactsQuery",
10129
+ additionalProperties: false
10130
+ });
10131
+ _Object_({
10132
+ kind: String$1({
10133
+ minLength: 1,
10134
+ maxLength: 100
10135
+ }),
10136
+ title: String$1({
10137
+ minLength: 1,
10138
+ maxLength: 255
10139
+ }),
10140
+ contentType: Optional(String$1({
10141
+ minLength: 1,
10142
+ maxLength: 200
10143
+ })),
10144
+ contentEncoding: Optional(String$1({
10145
+ minLength: 1,
10146
+ maxLength: 100
10147
+ }))
10148
+ }, {
10149
+ $id: "UploadTaskArtifactQuery",
10150
+ additionalProperties: false
10151
+ });
10152
+ String$1({
10153
+ $id: "TaskArtifactContent",
10154
+ description: "Task artifact content stream.",
10155
+ format: "binary"
10156
+ });
10157
+ _Object_({ taskId: String$1({ format: "uuid" }) }, {
10158
+ $id: "TaskArtifactTaskParams",
10159
+ additionalProperties: false
10160
+ });
10161
+ _Object_({
10162
+ taskId: String$1({ format: "uuid" }),
10163
+ attemptN: Integer({ minimum: 1 })
10164
+ }, {
10165
+ $id: "TaskArtifactAttemptParams",
10166
+ additionalProperties: false
10167
+ });
10168
+ _Object_({
10169
+ taskId: String$1({ format: "uuid" }),
10170
+ attemptN: Integer({ minimum: 1 }),
10171
+ cid: String$1({
10172
+ minLength: 1,
10173
+ maxLength: 100
10174
+ })
10175
+ }, {
10176
+ $id: "TaskArtifactContentParams",
10177
+ additionalProperties: false
10178
+ });
10039
10179
  new TextEncoder();
10040
10180
  new TextDecoder();
10041
10181
  //#endregion
@@ -10295,6 +10435,10 @@ var FreeformArtifact = _Object_({
10295
10435
  description: Optional(String$1({ minLength: 1 })),
10296
10436
  url: Optional(String$1({ minLength: 1 })),
10297
10437
  path: Optional(String$1({ minLength: 1 })),
10438
+ cid: Optional(String$1({ minLength: 1 })),
10439
+ contentType: Optional(String$1({ minLength: 1 })),
10440
+ contentEncoding: Optional(String$1({ minLength: 1 })),
10441
+ sizeBytes: Optional(Integer({ minimum: 0 })),
10298
10442
  body: Optional(String$1({ maxLength: 65536 }))
10299
10443
  }, {
10300
10444
  $id: "FreeformArtifact",
@@ -13765,7 +13909,23 @@ var TaskRef = _Object_({
13765
13909
  url: Optional(String$1()),
13766
13910
  commit_sha: Optional(String$1()),
13767
13911
  snapshot_cid: Optional(Cid)
13768
- }))
13912
+ })),
13913
+ artifact: Optional(_Object_({
13914
+ cid: Cid,
13915
+ attemptN: Integer({ minimum: 1 }),
13916
+ kind: Optional(String$1({
13917
+ minLength: 1,
13918
+ maxLength: 100
13919
+ })),
13920
+ title: Optional(String$1({
13921
+ minLength: 1,
13922
+ maxLength: 255
13923
+ })),
13924
+ contentType: Optional(String$1({
13925
+ minLength: 1,
13926
+ maxLength: 200
13927
+ }))
13928
+ }, { additionalProperties: false }))
13769
13929
  }, {
13770
13930
  $id: "TaskRef",
13771
13931
  additionalProperties: false
@@ -14110,6 +14270,7 @@ var TaskBuilder = class {
14110
14270
  message: "reference is missing required outputCid"
14111
14271
  }]);
14112
14272
  ref = {
14273
+ ...s,
14113
14274
  taskId: s.taskId ?? null,
14114
14275
  outputCid: s.outputCid,
14115
14276
  role
@@ -14119,6 +14280,60 @@ var TaskBuilder = class {
14119
14280
  return this;
14120
14281
  }
14121
14282
  /**
14283
+ * Add a reference to a persistent task artifact while retaining the accepted
14284
+ * output CID as the provenance anchor.
14285
+ *
14286
+ * @param source - A result reader, raw artifact reference, or `TaskRef`.
14287
+ * @param role - The role the referenced artifact plays.
14288
+ * @returns This builder, for chaining.
14289
+ * @throws {TaskBuildError} when output or artifact CID is missing.
14290
+ */
14291
+ artifactReference(source, role) {
14292
+ let ref;
14293
+ if ("artifactRef" in source && typeof source.artifactRef === "function") ref = source.artifactRef(role);
14294
+ else if ("artifact" in source && source.artifact?.cid) {
14295
+ if (typeof source.artifact.attemptN !== "number" || !Number.isInteger(source.artifact.attemptN) || source.artifact.attemptN < 1) throw new TaskBuildError([{
14296
+ field: "references/artifact/attemptN",
14297
+ message: "artifact reference is missing required attemptN"
14298
+ }]);
14299
+ ref = {
14300
+ ...source,
14301
+ role
14302
+ };
14303
+ } else {
14304
+ const s = source;
14305
+ const errors = [];
14306
+ if (!s.outputCid) errors.push({
14307
+ field: "references/outputCid",
14308
+ message: "reference is missing required outputCid"
14309
+ });
14310
+ if (!s.artifactCid) errors.push({
14311
+ field: "references/artifact/cid",
14312
+ message: "artifact reference is missing required cid"
14313
+ });
14314
+ if (typeof s.attemptN !== "number" || !Number.isInteger(s.attemptN) || s.attemptN < 1) errors.push({
14315
+ field: "references/artifact/attemptN",
14316
+ message: "artifact reference is missing required attemptN"
14317
+ });
14318
+ if (errors.length > 0) throw new TaskBuildError(errors);
14319
+ const attemptN = s.attemptN;
14320
+ ref = {
14321
+ taskId: s.taskId ?? null,
14322
+ outputCid: s.outputCid,
14323
+ role,
14324
+ artifact: {
14325
+ cid: s.artifactCid,
14326
+ attemptN,
14327
+ ...s.kind ? { kind: s.kind } : {},
14328
+ ...s.title ? { title: s.title } : {},
14329
+ ...s.contentType ? { contentType: s.contentType } : {}
14330
+ }
14331
+ };
14332
+ }
14333
+ this.refs.push(ref);
14334
+ return this;
14335
+ }
14336
+ /**
14122
14337
  * Set the owning team (required by the wire schema).
14123
14338
  *
14124
14339
  * @param teamId - Team UUID.
@@ -14496,6 +14711,34 @@ var TaskResultReader = class {
14496
14711
  role
14497
14712
  };
14498
14713
  }
14714
+ /**
14715
+ * Build a `TaskRef` that anchors a downstream task to this accepted output
14716
+ * and points at one persistent task artifact by CID.
14717
+ *
14718
+ * @param filter - Artifact object or a filter resolved against output artifacts.
14719
+ * @param role - The role this artifact plays in the downstream task.
14720
+ * @returns A `TaskRef` with `artifact.cid` populated.
14721
+ * @throws {TaskResultError} if no matching artifact has a CID.
14722
+ */
14723
+ artifactRef(filter, role) {
14724
+ const artifact = typeof filter === "object" && "cid" in filter && "kind" in filter ? filter : this.artifact(filter);
14725
+ if (!artifact?.cid) throw new TaskResultError([{
14726
+ field: "artifacts/cid",
14727
+ message: "no matching artifact with a cid"
14728
+ }]);
14729
+ return {
14730
+ taskId: this.taskId,
14731
+ outputCid: this.outputCid,
14732
+ role,
14733
+ artifact: {
14734
+ cid: artifact.cid,
14735
+ attemptN: this.accepted.attemptN,
14736
+ kind: artifact.kind,
14737
+ title: artifact.title,
14738
+ ...artifact.contentType ? { contentType: artifact.contentType } : {}
14739
+ }
14740
+ };
14741
+ }
14499
14742
  };
14500
14743
  /**
14501
14744
  * Validate and construct a {@link TaskResultReader} from a task and its
@@ -14520,6 +14763,63 @@ function createTasksNamespace(context) {
14520
14763
  auth
14521
14764
  }));
14522
14765
  },
14766
+ artifacts: {
14767
+ async upload(path, body, query, options) {
14768
+ return unwrapResult(await uploadTaskArtifact({
14769
+ auth,
14770
+ body,
14771
+ client,
14772
+ duplex: "half",
14773
+ headers: {
14774
+ ...requiredTeamHeaders(options),
14775
+ "content-type": "application/octet-stream"
14776
+ },
14777
+ path,
14778
+ query
14779
+ }));
14780
+ },
14781
+ async list(taskId, options, query) {
14782
+ return unwrapResult(await listTaskArtifacts({
14783
+ client,
14784
+ auth,
14785
+ headers: requiredTeamHeaders(options),
14786
+ path: { taskId },
14787
+ query
14788
+ })).artifacts;
14789
+ },
14790
+ async listPage(taskId, query, options) {
14791
+ return unwrapResult(await listTaskArtifacts({
14792
+ client,
14793
+ auth,
14794
+ headers: requiredTeamHeaders(options),
14795
+ path: { taskId },
14796
+ query
14797
+ }));
14798
+ },
14799
+ async download(path, options) {
14800
+ const result = await client.request({
14801
+ auth,
14802
+ headers: requiredTeamHeaders(options),
14803
+ method: "GET",
14804
+ parseAs: "stream",
14805
+ path,
14806
+ security: [{
14807
+ scheme: "bearer",
14808
+ type: "http"
14809
+ }],
14810
+ url: "/tasks/{taskId}/attempts/{attemptN}/artifacts/{cid}/content"
14811
+ });
14812
+ const normalizedStream = normalizeDownloadStream(unwrapResult(result));
14813
+ if (normalizedStream) return {
14814
+ artifactId: header(result.response, "x-moltnet-task-artifact-id"),
14815
+ cid: header(result.response, "x-moltnet-task-artifact-cid"),
14816
+ contentEncoding: header(result.response, "x-moltnet-task-artifact-content-encoding"),
14817
+ contentType: header(result.response, "x-moltnet-task-artifact-content-type"),
14818
+ stream: normalizedStream
14819
+ };
14820
+ throw new MoltNetError("Unexpected task artifact download response stream", { code: "INVALID_RESPONSE" });
14821
+ }
14822
+ },
14523
14823
  async list(query, options) {
14524
14824
  return unwrapResult(await listTasks({
14525
14825
  client,
@@ -14688,6 +14988,33 @@ function createTasksNamespace(context) {
14688
14988
  }
14689
14989
  };
14690
14990
  }
14991
+ function header(response, name) {
14992
+ const value = response?.headers.get(name) ?? null;
14993
+ return value === "" ? null : value;
14994
+ }
14995
+ function normalizeDownloadStream(stream) {
14996
+ if (isAsyncIterable(stream)) return stream;
14997
+ if (isReadableStream(stream)) return readableStreamToAsyncIterable(stream);
14998
+ return null;
14999
+ }
15000
+ function isAsyncIterable(value) {
15001
+ return typeof value === "object" && value !== null && Symbol.asyncIterator in value && typeof value[Symbol.asyncIterator] === "function";
15002
+ }
15003
+ function isReadableStream(value) {
15004
+ return typeof value === "object" && value !== null && "getReader" in value && typeof value.getReader === "function";
15005
+ }
15006
+ async function* readableStreamToAsyncIterable(stream) {
15007
+ const reader = stream.getReader();
15008
+ try {
15009
+ while (true) {
15010
+ const result = await reader.read();
15011
+ if (result.done) return;
15012
+ yield result.value;
15013
+ }
15014
+ } finally {
15015
+ reader.releaseLock();
15016
+ }
15017
+ }
14691
15018
  //#endregion
14692
15019
  //#region ../sdk/src/namespaces/teams.ts
14693
15020
  function createTeamsNamespace(context) {
@@ -19,16 +19,13 @@ var init = (RED) => {
19
19
  } : def.artifactKind : void 0;
20
20
  let artifactBody;
21
21
  const artifact = filter ? reader.artifact(filter) : void 0;
22
- if (filter && artifact && typeof artifact.body === "string") try {
23
- artifactBody = JSON.parse(artifact.body);
24
- } catch {
25
- artifactBody = void 0;
26
- }
22
+ if (filter && artifact && typeof artifact.body === "string") artifactBody = reader.artifactBody(filter);
27
23
  const out = RED.util.cloneMessage(msg);
28
24
  out.payload = reader.output;
29
25
  out.result = {
30
26
  summary: reader.summary,
31
27
  outputRef: reader.outputRef(role),
28
+ artifactRef: artifact?.cid !== void 0 ? reader.artifactRef(artifact, role) : void 0,
32
29
  artifact,
33
30
  artifactBody,
34
31
  accepted: reader.accepted,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/node-red-contrib-core",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Node-RED nodes for the MoltNet API",
6
6
  "keywords": [
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "main": "dist/nodes/agent.js",
40
40
  "dependencies": {
41
- "@themoltnet/sdk": "0.114.0"
41
+ "@themoltnet/sdk": "0.115.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^22.19.0",