@ingram-cloud/pulumi 1.3.0 → 2.0.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/README.md +8 -1
- package/dist/resources.d.ts +37 -0
- package/dist/resources.js +213 -5
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ const curator = new ic.IcAgent("curator", {
|
|
|
83
83
|
autoMemory: AGENT_SPECS.curator.auto_memory,
|
|
84
84
|
// memoryConsolidation: true, // opt into background consolidation (billed)
|
|
85
85
|
// variables: [...], enabledHostedTools: [...], rolloutPercent: 100,
|
|
86
|
+
// mcpServers: ["sheets"], // scope runs to these registered MCP servers (omit = all)
|
|
86
87
|
});
|
|
87
88
|
|
|
88
89
|
export const curatorAgentId = curator.agentId;
|
|
@@ -150,7 +151,7 @@ export const pageUrl = page.pageUrl; // https://cloud.ingram.tech/hosted/dep_…
|
|
|
150
151
|
// Your own server (raw URL).
|
|
151
152
|
new ic.IcMcpServer("thornhill-mcp", {
|
|
152
153
|
...conn, serverName: "thornhill", url: `${APP_URL}/api/mcp`,
|
|
153
|
-
authKind: "
|
|
154
|
+
authKind: "bearer", secret: mcpSecret,
|
|
154
155
|
});
|
|
155
156
|
|
|
156
157
|
// An `oauth`-kind server forwards each end-user's own stored token; its
|
|
@@ -251,3 +252,9 @@ usually unnecessary — a plain `pulumi up` will reconcile the live agent.)
|
|
|
251
252
|
`pulumi refresh` prunes a resource deleted out-of-band — e.g. after an IC DB
|
|
252
253
|
reset, `pulumi refresh && pulumi up` recreates it, no `pulumi state delete`.
|
|
253
254
|
Non-404 errors still throw, so a transient API blip can't drop it from state.
|
|
255
|
+
- `IcMcpServer` `read` also round-trips the live `url` / `authKind` /
|
|
256
|
+
`authProvider` (raw registrations only — catalog presets supply these
|
|
257
|
+
server-side), so `pulumi refresh && pulumi up` detects and repairs server-side
|
|
258
|
+
drift such as a lost auth block. Write-only fields (`secret`) can't round-trip
|
|
259
|
+
and stay diff-by-state. Dynamic providers run the code serialized into state,
|
|
260
|
+
so drift detection starts after the first `pulumi up` with this version.
|
package/dist/resources.d.ts
CHANGED
|
@@ -85,6 +85,14 @@ export interface IcAgentArgs {
|
|
|
85
85
|
instructions?: pulumi.Input<string>;
|
|
86
86
|
model?: pulumi.Input<string>;
|
|
87
87
|
enabledHostedTools?: pulumi.Input<string[]>;
|
|
88
|
+
/** Scope runs to these registered MCP servers (by name). Omitted = all. */
|
|
89
|
+
mcpServers?: pulumi.Input<string[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Vector store ids (`vs_…`) whose contents this agent can retrieve over. Folds
|
|
92
|
+
* into the content signature like `enabledHostedTools`, so a change publishes and
|
|
93
|
+
* rolls out a new version. Pair with {@link IcVectorStore} to IaC the stores.
|
|
94
|
+
*/
|
|
95
|
+
vectorStoreIds?: pulumi.Input<string[]>;
|
|
88
96
|
autoMemory?: pulumi.Input<boolean>;
|
|
89
97
|
/** Opt into observational-memory consolidation (background, billed). Default off. */
|
|
90
98
|
memoryConsolidation?: pulumi.Input<boolean>;
|
|
@@ -109,6 +117,35 @@ export declare class IcAgent extends pulumi.dynamic.Resource {
|
|
|
109
117
|
readonly activeVersion: pulumi.Output<number>;
|
|
110
118
|
constructor(name: string, args: IcAgentArgs, opts?: pulumi.CustomResourceOptions);
|
|
111
119
|
}
|
|
120
|
+
/** One source file on an {@link IcVectorStore}, provided by local path. */
|
|
121
|
+
export interface VectorStoreFile {
|
|
122
|
+
/** Absolute path to the file to ingest (read at `pulumi up`, like `htmlPath`). */
|
|
123
|
+
path: string;
|
|
124
|
+
/** Per-file chunking override (the `chunking_strategy` wire shape); defaults to
|
|
125
|
+
* the server default (`auto`). */
|
|
126
|
+
chunkingStrategy?: Record<string, unknown>;
|
|
127
|
+
}
|
|
128
|
+
export interface IcVectorStoreArgs {
|
|
129
|
+
baseUrl: pulumi.Input<string>;
|
|
130
|
+
token: pulumi.Input<string>;
|
|
131
|
+
/** Display name. */
|
|
132
|
+
name?: pulumi.Input<string>;
|
|
133
|
+
description?: pulumi.Input<string>;
|
|
134
|
+
/** Arbitrary key/value metadata stored on the vector store. */
|
|
135
|
+
metadata?: pulumi.Input<Record<string, unknown>>;
|
|
136
|
+
/**
|
|
137
|
+
* Source files to ingest, each declared by an absolute local `path` (read at
|
|
138
|
+
* `pulumi up`, like a UI template's `htmlPath`). A file's sha256 tracks drift:
|
|
139
|
+
* edit it and it re-uploads + re-attaches, remove it and it detaches. Attaching
|
|
140
|
+
* starts async ingest server-side; this resource does not block on indexing.
|
|
141
|
+
*/
|
|
142
|
+
files?: pulumi.Input<VectorStoreFile[]>;
|
|
143
|
+
}
|
|
144
|
+
export declare class IcVectorStore extends pulumi.dynamic.Resource {
|
|
145
|
+
/** The `vs_…` id (same as `.id`, exposed for convenience). */
|
|
146
|
+
readonly vectorStoreId: pulumi.Output<string>;
|
|
147
|
+
constructor(name: string, args: IcVectorStoreArgs, opts?: pulumi.CustomResourceOptions);
|
|
148
|
+
}
|
|
112
149
|
export interface IcMcpServerArgs {
|
|
113
150
|
baseUrl: pulumi.Input<string>;
|
|
114
151
|
token: pulumi.Input<string>;
|
package/dist/resources.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.IcWebPage = exports.IcProjectToken = exports.IcProject = exports.IcModelKey = exports.IcWebhook = exports.IcEmail = exports.IcWhatsAppConfig = exports.IcOauthProvider = exports.IcTelegramBot = exports.IcMcpServer = exports.IcAgent = exports.IC_API_VERSION = void 0;
|
|
36
|
+
exports.IcWebPage = exports.IcProjectToken = exports.IcProject = exports.IcModelKey = exports.IcWebhook = exports.IcEmail = exports.IcWhatsAppConfig = exports.IcOauthProvider = exports.IcTelegramBot = exports.IcMcpServer = exports.IcVectorStore = exports.IcAgent = exports.IC_API_VERSION = void 0;
|
|
37
37
|
/**
|
|
38
38
|
* Ingram Cloud /v1 tenant configuration as Pulumi dynamic resources.
|
|
39
39
|
*
|
|
@@ -143,6 +143,11 @@ function makePutResource(cfg) {
|
|
|
143
143
|
async diff(_id, olds, news) {
|
|
144
144
|
return simpleDiff(olds, news, cfg.diff);
|
|
145
145
|
},
|
|
146
|
+
async read(id, props) {
|
|
147
|
+
if (!cfg.readProps || !props?.baseUrl || !props?.token)
|
|
148
|
+
return { id, props };
|
|
149
|
+
return read404(() => icRequest(props.baseUrl, props.token, "GET", cfg.path(props)), (res) => ({ id, props: { ...props, ...cfg.readProps(props, res) } }));
|
|
150
|
+
},
|
|
146
151
|
};
|
|
147
152
|
}
|
|
148
153
|
// Read each template's HTML bundle (from `htmlPath` or inline `html`), hash the
|
|
@@ -238,6 +243,8 @@ function agentBody(i) {
|
|
|
238
243
|
instructions: i.instructions ?? null,
|
|
239
244
|
model: i.model ?? null,
|
|
240
245
|
enabled_hosted_tools: i.enabledHostedTools ?? [],
|
|
246
|
+
mcp_servers: i.mcpServers ?? null,
|
|
247
|
+
vector_store_ids: i.vectorStoreIds ?? [],
|
|
241
248
|
auto_memory: i.autoMemory ?? null,
|
|
242
249
|
memory_consolidation: i.memoryConsolidation ?? null,
|
|
243
250
|
variables: i.variables ?? [],
|
|
@@ -276,6 +283,14 @@ function agentContentSig(s) {
|
|
|
276
283
|
const ui = uiResourcesSig(s.ui_resources);
|
|
277
284
|
if (ui.length)
|
|
278
285
|
base.ui_resources = ui;
|
|
286
|
+
// Same discipline for mcp_servers: unset (= all) stays out of the signature.
|
|
287
|
+
if (s.mcp_servers != null)
|
|
288
|
+
base.mcp_servers = [...s.mcp_servers].sort();
|
|
289
|
+
// And for vector stores: omit when empty so agents without any keep a
|
|
290
|
+
// byte-identical signature to pre-vectorStoreIds releases.
|
|
291
|
+
const vs = [...(s.vector_store_ids ?? [])].sort();
|
|
292
|
+
if (vs.length)
|
|
293
|
+
base.vector_store_ids = vs;
|
|
279
294
|
return JSON.stringify(base);
|
|
280
295
|
}
|
|
281
296
|
// Map the camelCase resource inputs onto the canonical snapshot shape.
|
|
@@ -284,6 +299,8 @@ function inputsToSnapshot(i) {
|
|
|
284
299
|
instructions: i.instructions,
|
|
285
300
|
model: i.model,
|
|
286
301
|
enabled_hosted_tools: i.enabledHostedTools,
|
|
302
|
+
mcp_servers: i.mcpServers,
|
|
303
|
+
vector_store_ids: i.vectorStoreIds,
|
|
287
304
|
auto_memory: i.autoMemory,
|
|
288
305
|
memory_consolidation: i.memoryConsolidation,
|
|
289
306
|
variables: i.variables,
|
|
@@ -299,7 +316,7 @@ function inputsToSnapshot(i) {
|
|
|
299
316
|
};
|
|
300
317
|
}
|
|
301
318
|
async function findAgentBySlug(baseUrl, token, slug) {
|
|
302
|
-
const res = await icRequest(baseUrl, token, "GET", "/v1/agents");
|
|
319
|
+
const res = await icRequest(baseUrl, token, "GET", "/v1/agents?limit=200");
|
|
303
320
|
return (res.data ?? []).find((b) => b.slug === slug) ?? null;
|
|
304
321
|
}
|
|
305
322
|
// Signature of the snapshot currently published as the active version, or null
|
|
@@ -307,7 +324,7 @@ async function findAgentBySlug(baseUrl, token, slug) {
|
|
|
307
324
|
async function activeSnapshotSig(baseUrl, token, id, activeVersion) {
|
|
308
325
|
if (!activeVersion)
|
|
309
326
|
return null;
|
|
310
|
-
const res = await icRequest(baseUrl, token, "GET", `/v1/agents/${id}/versions`);
|
|
327
|
+
const res = await icRequest(baseUrl, token, "GET", `/v1/agents/${id}/versions?limit=200`);
|
|
311
328
|
const v = (res.data ?? []).find((x) => x.version === activeVersion);
|
|
312
329
|
if (!v)
|
|
313
330
|
return null;
|
|
@@ -430,6 +447,7 @@ const agentProvider = {
|
|
|
430
447
|
instructions: d.instructions ?? undefined,
|
|
431
448
|
model: d.model ?? undefined,
|
|
432
449
|
enabledHostedTools: d.enabled_hosted_tools ?? [],
|
|
450
|
+
vectorStoreIds: d.vector_store_ids ?? [],
|
|
433
451
|
autoMemory: d.auto_memory ?? undefined,
|
|
434
452
|
memoryConsolidation: d.memory_consolidation ?? undefined,
|
|
435
453
|
variables: d.variables ?? [],
|
|
@@ -444,6 +462,8 @@ class IcAgent extends pulumi.dynamic.Resource {
|
|
|
444
462
|
instructions: undefined,
|
|
445
463
|
model: undefined,
|
|
446
464
|
enabledHostedTools: undefined,
|
|
465
|
+
mcpServers: undefined,
|
|
466
|
+
vectorStoreIds: undefined,
|
|
447
467
|
autoMemory: undefined,
|
|
448
468
|
memoryConsolidation: undefined,
|
|
449
469
|
variables: undefined,
|
|
@@ -461,6 +481,181 @@ class IcAgent extends pulumi.dynamic.Resource {
|
|
|
461
481
|
}
|
|
462
482
|
}
|
|
463
483
|
exports.IcAgent = IcAgent;
|
|
484
|
+
// Read each declared file's bytes and hash them (same sha256-hex the API keys
|
|
485
|
+
// files by) so an edit shows up in the file signature. Module-scope + node
|
|
486
|
+
// built-ins required inside for Pulumi's closure serialization.
|
|
487
|
+
function resolveVsFiles(files) {
|
|
488
|
+
if (!files?.length)
|
|
489
|
+
return [];
|
|
490
|
+
const { createHash } = require("node:crypto");
|
|
491
|
+
return files.map((f) => {
|
|
492
|
+
if (!f.path)
|
|
493
|
+
throw new Error("vectorStore file: `path` is required");
|
|
494
|
+
const bytes = require("node:fs").readFileSync(f.path);
|
|
495
|
+
return {
|
|
496
|
+
path: f.path,
|
|
497
|
+
bytes,
|
|
498
|
+
contentHash: createHash("sha256").update(bytes).digest("hex"),
|
|
499
|
+
chunkingStrategy: f.chunkingStrategy,
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
// Multipart upload of one file to POST /v1/files (purpose `assistants`, the
|
|
504
|
+
// vector-store source purpose) → the new `file_…` id. Not `icRequest` (that
|
|
505
|
+
// JSON-encodes the body); uses global FormData/File (Node ≥18).
|
|
506
|
+
async function uploadFile(baseUrl, token, bytes, filename) {
|
|
507
|
+
const form = new FormData();
|
|
508
|
+
form.set("file", new File([new Uint8Array(bytes)], filename, {
|
|
509
|
+
type: "application/octet-stream",
|
|
510
|
+
}));
|
|
511
|
+
form.set("purpose", "assistants");
|
|
512
|
+
const res = await fetch(`${baseUrl}/v1/files`, {
|
|
513
|
+
method: "POST",
|
|
514
|
+
headers: { Authorization: `Bearer ${token}`, "IC-Api-Version": exports.IC_API_VERSION },
|
|
515
|
+
body: form,
|
|
516
|
+
});
|
|
517
|
+
if (!res.ok) {
|
|
518
|
+
const err = new Error(`IC POST /v1/files → ${res.status}: ${(await res.text()).slice(0, 400)}`);
|
|
519
|
+
err.status = res.status;
|
|
520
|
+
throw err;
|
|
521
|
+
}
|
|
522
|
+
return (await res.json()).id;
|
|
523
|
+
}
|
|
524
|
+
const vsBasename = (p) => p.split(/[\\/]/).pop() || p;
|
|
525
|
+
// The store's mutable fields (POST /v1/vector_stores on create, POST
|
|
526
|
+
// /v1/vector_stores/{id} to modify). Only send keys the caller set.
|
|
527
|
+
function vsBody(i) {
|
|
528
|
+
const body = {};
|
|
529
|
+
if (i.name !== undefined)
|
|
530
|
+
body.name = i.name;
|
|
531
|
+
if (i.description !== undefined)
|
|
532
|
+
body.description = i.description;
|
|
533
|
+
if (i.metadata !== undefined)
|
|
534
|
+
body.metadata = i.metadata;
|
|
535
|
+
return body;
|
|
536
|
+
}
|
|
537
|
+
// Upload one file's bytes and attach the resulting id to the store.
|
|
538
|
+
async function attachVsFile(i, id, f) {
|
|
539
|
+
const fileId = await uploadFile(i.baseUrl, i.token, f.bytes, vsBasename(f.path));
|
|
540
|
+
await icRequest(i.baseUrl, i.token, "POST", `/v1/vector_stores/${id}/files`, {
|
|
541
|
+
file_id: fileId,
|
|
542
|
+
...(f.chunkingStrategy ? { chunking_strategy: f.chunkingStrategy } : {}),
|
|
543
|
+
});
|
|
544
|
+
return { path: f.path, contentHash: f.contentHash, fileId };
|
|
545
|
+
}
|
|
546
|
+
// Reconcile attachments against the declared set: (re)upload+attach any new-or-
|
|
547
|
+
// changed file, detach any whose path was dropped or whose bytes changed. Returns
|
|
548
|
+
// the new file-state list to store as an output. The store-file id IS the
|
|
549
|
+
// `file_…` id, so detach targets `/files/{fileId}`.
|
|
550
|
+
async function syncVsFiles(i, id, prior) {
|
|
551
|
+
const desired = resolveVsFiles(i.files);
|
|
552
|
+
const byPath = new Map(prior.map((p) => [p.path, p]));
|
|
553
|
+
const next = [];
|
|
554
|
+
for (const f of desired) {
|
|
555
|
+
const cur = byPath.get(f.path);
|
|
556
|
+
if (cur && cur.contentHash === f.contentHash) {
|
|
557
|
+
next.push(cur); // unchanged bytes — keep the existing attachment
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
if (cur)
|
|
561
|
+
// bytes changed → detach the stale file before re-uploading
|
|
562
|
+
await icRequest(i.baseUrl, i.token, "DELETE", `/v1/vector_stores/${id}/files/${cur.fileId}`);
|
|
563
|
+
next.push(await attachVsFile(i, id, f));
|
|
564
|
+
}
|
|
565
|
+
const keep = new Set(desired.map((f) => f.path));
|
|
566
|
+
for (const p of prior)
|
|
567
|
+
if (!keep.has(p.path))
|
|
568
|
+
await icRequest(i.baseUrl, i.token, "DELETE", `/v1/vector_stores/${id}/files/${p.fileId}`);
|
|
569
|
+
return next;
|
|
570
|
+
}
|
|
571
|
+
// Canonical, path-sorted signature of the declared files (path + content hash +
|
|
572
|
+
// chunking), so a file edit/add/remove is exactly one diff. Empty ⇒ "[]".
|
|
573
|
+
function vsFilesSig(files) {
|
|
574
|
+
return JSON.stringify(resolveVsFiles(files)
|
|
575
|
+
.map((f) => ({
|
|
576
|
+
path: f.path,
|
|
577
|
+
content_hash: f.contentHash,
|
|
578
|
+
chunking: f.chunkingStrategy ?? null,
|
|
579
|
+
}))
|
|
580
|
+
.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)));
|
|
581
|
+
}
|
|
582
|
+
const vectorStoreProvider = {
|
|
583
|
+
async create(i) {
|
|
584
|
+
const res = await icRequest(i.baseUrl, i.token, "POST", "/v1/vector_stores", vsBody(i));
|
|
585
|
+
const fileState = await syncVsFiles(i, res.id, []);
|
|
586
|
+
return {
|
|
587
|
+
id: res.id,
|
|
588
|
+
outs: {
|
|
589
|
+
...i,
|
|
590
|
+
vectorStoreId: res.id,
|
|
591
|
+
fileState,
|
|
592
|
+
filesSig: vsFilesSig(i.files),
|
|
593
|
+
},
|
|
594
|
+
};
|
|
595
|
+
},
|
|
596
|
+
async update(id, olds, news) {
|
|
597
|
+
const body = vsBody(news);
|
|
598
|
+
if (Object.keys(body).length)
|
|
599
|
+
await icRequest(news.baseUrl, news.token, "POST", `/v1/vector_stores/${id}`, body);
|
|
600
|
+
const fileState = await syncVsFiles(news, id, olds.fileState ?? []);
|
|
601
|
+
return {
|
|
602
|
+
outs: {
|
|
603
|
+
...news,
|
|
604
|
+
vectorStoreId: id,
|
|
605
|
+
fileState,
|
|
606
|
+
filesSig: vsFilesSig(news.files),
|
|
607
|
+
},
|
|
608
|
+
};
|
|
609
|
+
},
|
|
610
|
+
async delete(id, props) {
|
|
611
|
+
await icRequest(props.baseUrl, props.token, "DELETE", `/v1/vector_stores/${id}`);
|
|
612
|
+
},
|
|
613
|
+
async diff(_id, olds, news) {
|
|
614
|
+
const scalarChanged = (olds.name ?? undefined) !== (news.name ?? undefined) ||
|
|
615
|
+
(olds.description ?? undefined) !== (news.description ?? undefined);
|
|
616
|
+
const metaChanged = JSON.stringify(olds.metadata ?? null) !==
|
|
617
|
+
JSON.stringify(news.metadata ?? null);
|
|
618
|
+
// Compare against the sig STORED at the last apply (not a re-resolve of olds):
|
|
619
|
+
// a file-backed path edits the same bytes, so re-reading olds would hash the
|
|
620
|
+
// new bytes and hide the change (same reasoning as the agent diff).
|
|
621
|
+
const oldSig = olds.filesSig ?? vsFilesSig(olds.files);
|
|
622
|
+
const filesChanged = oldSig !== vsFilesSig(news.files);
|
|
623
|
+
return { changes: scalarChanged || metaChanged || filesChanged };
|
|
624
|
+
},
|
|
625
|
+
// Adopt a store a script already created (`pulumi import <id>`). Local file
|
|
626
|
+
// attachments can't be reconstructed from the server (no local paths), so this
|
|
627
|
+
// recovers only the store's own fields; declare `files` to (re)assert them.
|
|
628
|
+
async read(id, props) {
|
|
629
|
+
return read404(() => icRequest(props.baseUrl, props.token, "GET", `/v1/vector_stores/${id}`), (vs) => {
|
|
630
|
+
if (!vs || !vs.id)
|
|
631
|
+
return { id: "" };
|
|
632
|
+
return {
|
|
633
|
+
id,
|
|
634
|
+
props: {
|
|
635
|
+
...props,
|
|
636
|
+
name: vs.name ?? undefined,
|
|
637
|
+
description: vs.description ?? undefined,
|
|
638
|
+
metadata: vs.metadata ?? undefined,
|
|
639
|
+
},
|
|
640
|
+
};
|
|
641
|
+
});
|
|
642
|
+
},
|
|
643
|
+
};
|
|
644
|
+
class IcVectorStore extends pulumi.dynamic.Resource {
|
|
645
|
+
constructor(name, args, opts) {
|
|
646
|
+
super(vectorStoreProvider, name, {
|
|
647
|
+
name: undefined,
|
|
648
|
+
description: undefined,
|
|
649
|
+
metadata: undefined,
|
|
650
|
+
files: undefined,
|
|
651
|
+
vectorStoreId: undefined,
|
|
652
|
+
fileState: undefined,
|
|
653
|
+
filesSig: undefined,
|
|
654
|
+
...args,
|
|
655
|
+
}, { ...opts, additionalSecretOutputs: ["token"] });
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
exports.IcVectorStore = IcVectorStore;
|
|
464
659
|
function mcpBody(i) {
|
|
465
660
|
const auth = { kind: i.authKind };
|
|
466
661
|
if (i.authProvider)
|
|
@@ -488,6 +683,19 @@ const mcpProvider = makePutResource({
|
|
|
488
683
|
toolsDiscovered: res.tools_discovered ?? 0,
|
|
489
684
|
discoveryError: res.discovery_error ?? null,
|
|
490
685
|
}),
|
|
686
|
+
// `pulumi refresh` round-trips the security-relevant fields, so a live auth
|
|
687
|
+
// downgrade (e.g. oauth silently reverting to none) shows up as a diff and the
|
|
688
|
+
// next `up` re-pushes the declared config. Catalog presets supply url/auth
|
|
689
|
+
// server-side — omitted inputs are correct there, so nothing is overlaid.
|
|
690
|
+
readProps: (i, res) => {
|
|
691
|
+
if (i.catalog)
|
|
692
|
+
return {};
|
|
693
|
+
return {
|
|
694
|
+
url: res.url ?? i.url,
|
|
695
|
+
authKind: res.auth?.kind ?? i.authKind,
|
|
696
|
+
authProvider: res.auth?.provider ?? undefined,
|
|
697
|
+
};
|
|
698
|
+
},
|
|
491
699
|
diff: {
|
|
492
700
|
replaceKeys: ["serverName"],
|
|
493
701
|
scalarKeys: [
|
|
@@ -508,7 +716,7 @@ const mcpProvider = makePutResource({
|
|
|
508
716
|
class IcMcpServer extends pulumi.dynamic.Resource {
|
|
509
717
|
constructor(name, args, opts) {
|
|
510
718
|
super(mcpProvider, name, {
|
|
511
|
-
authKind: args.catalog ? undefined : "
|
|
719
|
+
authKind: args.catalog ? undefined : "bearer",
|
|
512
720
|
url: undefined,
|
|
513
721
|
catalog: undefined,
|
|
514
722
|
authProvider: undefined,
|
|
@@ -696,7 +904,7 @@ const webhookProvider = {
|
|
|
696
904
|
// Enables `pulumi import` of a webhook a script already created (id is the
|
|
697
905
|
// import id). The signing secret is intentionally not recoverable.
|
|
698
906
|
async read(id, props) {
|
|
699
|
-
const list = await icRequest(props.baseUrl, props.token, "GET", "/v1/tenant/webhooks");
|
|
907
|
+
const list = await icRequest(props.baseUrl, props.token, "GET", "/v1/tenant/webhooks?limit=200");
|
|
700
908
|
const hit = (list.data ?? []).find((w) => w.id === id);
|
|
701
909
|
// Absent from the list → gone server-side; empty id lets refresh prune it.
|
|
702
910
|
if (!hit)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingram-cloud/pulumi",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Pulumi dynamic resources for the Ingram Cloud /v1 API — projects, project tokens, agents, MCP servers, channels, webhooks, model keys.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://cloud.ingram.tech",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@ingram-tech/oxlint-config": "^0.2.2",
|
|
32
|
-
"@pulumi/pulumi": "^3.
|
|
32
|
+
"@pulumi/pulumi": "^3.253.0",
|
|
33
33
|
"@types/node": "^26.1.1",
|
|
34
|
-
"oxfmt": "^0.
|
|
35
|
-
"oxlint": "^1.
|
|
34
|
+
"oxfmt": "^0.59.0",
|
|
35
|
+
"oxlint": "^1.74.0",
|
|
36
36
|
"typescript": "^7.0.2"
|
|
37
37
|
}
|
|
38
38
|
}
|