@agentforge-io/sdk-server 4.14.0 → 4.16.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/client.d.ts CHANGED
@@ -10,6 +10,7 @@ import { SecretsResource } from './resources/secrets';
10
10
  import { TeamsResource } from './resources/teams';
11
11
  import { TemplatesResource } from './resources/templates';
12
12
  import { TenantConfigResource } from './resources/config';
13
+ import { CatalogResource } from './resources/catalog';
13
14
  import { BusinessRolesResource } from './resources/business-roles';
14
15
  import { ToolsResource } from './resources/tools';
15
16
  export interface AgentForgeClientOptions {
@@ -56,6 +57,10 @@ export interface RequestOptions {
56
57
  * caller already hashed/signed this EXACT string and re-serializing the
57
58
  * same object could (in principle) produce a different byte sequence. */
58
59
  rawBody?: string;
60
+ /** Multipart body (file uploads). Sent as-is; the content-type with its
61
+ * boundary is set by fetch, so none is added here. Mutually exclusive with
62
+ * `rawBody`. */
63
+ formData?: FormData;
59
64
  /** ms before the request aborts. `null` disables the timeout entirely —
60
65
  * used for chat streaming, where a tool-calling turn can legitimately
61
66
  * run long. Defaults to the client's `timeoutMs`. */
@@ -88,6 +93,7 @@ export declare class AgentForgeClient {
88
93
  readonly templates: TemplatesResource;
89
94
  readonly config: TenantConfigResource;
90
95
  readonly businessRoles: BusinessRolesResource;
96
+ readonly catalog: CatalogResource;
91
97
  constructor(opts: AgentForgeClientOptions);
92
98
  /**
93
99
  * A client that acts inside `tenantId`, a tenant where this App is
package/dist/client.js CHANGED
@@ -32,6 +32,7 @@ const secrets_1 = require("./resources/secrets");
32
32
  const teams_1 = require("./resources/teams");
33
33
  const templates_1 = require("./resources/templates");
34
34
  const config_1 = require("./resources/config");
35
+ const catalog_1 = require("./resources/catalog");
35
36
  const business_roles_1 = require("./resources/business-roles");
36
37
  const tools_1 = require("./resources/tools");
37
38
  /** Header that selects an installed tenant for an App secret. */
@@ -74,6 +75,7 @@ class AgentForgeClient {
74
75
  this.templates = new templates_1.TemplatesResource(this);
75
76
  this.config = new config_1.TenantConfigResource(this);
76
77
  this.businessRoles = new business_roles_1.BusinessRolesResource(this);
78
+ this.catalog = new catalog_1.CatalogResource(this);
77
79
  }
78
80
  /**
79
81
  * A client that acts inside `tenantId`, a tenant where this App is
@@ -183,7 +185,7 @@ class AgentForgeClient {
183
185
  ...(this.tenantId ? { [exports.INSTALLED_TENANT_HEADER]: this.tenantId } : {}),
184
186
  ...(opts?.headers ?? {}),
185
187
  },
186
- body: opts?.rawBody,
188
+ body: opts?.formData ?? opts?.rawBody,
187
189
  signal: controller.signal,
188
190
  });
189
191
  }
package/dist/errors.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  export declare class AgentForgeError extends Error {
2
2
  readonly status: number;
3
3
  readonly body?: string;
4
- constructor(status: number, message: string, body?: string);
4
+ /** Machine-readable error code from the response body (`{ code }`, or the
5
+ * legacy `{ error }`), when the platform sent one — e.g. `FILE_EMPTY_FILE`,
6
+ * `INVALID_MAPPING`, `CATALOG_NOT_FOUND`. Also set on 404/401/403 errors. */
7
+ readonly code?: string;
8
+ constructor(status: number, message: string, body?: string, code?: string);
5
9
  }
6
10
  export declare class AgentForgeAuthError extends AgentForgeError {
7
11
  constructor(status: 401 | 403, message: string, body?: string);
package/dist/errors.js CHANGED
@@ -4,14 +4,37 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.AgentForgeNetworkError = exports.AgentForgeNotFoundError = exports.AgentForgeAuthError = exports.AgentForgeError = void 0;
6
6
  class AgentForgeError extends Error {
7
- constructor(status, message, body) {
7
+ constructor(status, message, body, code) {
8
8
  super(message);
9
9
  this.name = 'AgentForgeError';
10
10
  this.status = status;
11
11
  this.body = body;
12
+ this.code = code ?? parseErrorCode(body);
12
13
  }
13
14
  }
14
15
  exports.AgentForgeError = AgentForgeError;
16
+ const ERROR_CODE = /^[A-Z][A-Z0-9_]+$/;
17
+ function parseErrorCode(body) {
18
+ if (!body)
19
+ return undefined;
20
+ try {
21
+ const parsed = JSON.parse(body);
22
+ if (typeof parsed.code === 'string')
23
+ return parsed.code;
24
+ // Nest's default body puts the status text in `error` ("Bad Request"):
25
+ // only a code-shaped value counts.
26
+ if (typeof parsed.error === 'string' && ERROR_CODE.test(parsed.error))
27
+ return parsed.error;
28
+ // Nest wraps `{ code }` payloads one level down in some versions.
29
+ const msg = parsed.message;
30
+ if (msg && typeof msg === 'object' && typeof msg.code === 'string')
31
+ return msg.code;
32
+ }
33
+ catch {
34
+ /* non-JSON body */
35
+ }
36
+ return undefined;
37
+ }
15
38
  class AgentForgeAuthError extends AgentForgeError {
16
39
  constructor(status, message, body) {
17
40
  super(status, message, body);
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { AgentForgeClient, INSTALLED_TENANT_HEADER } from './client';
2
2
  export type { AgentForgeClientOptions, RequestOptions } from './client';
3
3
  export { AgentForgeError, AgentForgeAuthError, AgentForgeNotFoundError, AgentForgeNetworkError, } from './errors';
4
4
  export { TOOL_CALLBACK_HEADERS, ToolCallbackSignatureError, signToolCallbackPayload, verifyToolCallbackSignature, } from './webhooks';
5
- export type { AgentMe, AgentSummary, AppUserConnectorStatus, ApprovalCopyBundle, ChannelContext, ChatStreamChunk, ChatStreamEvent, ChatTokenRecord, ConnectorDefaultsResult, ConnectorDefaultsSource, ConnectorResourceItem, ConnectorStatus, ConnectorToolInfo, ConversationHistory, ConversationStatus, CreateAgentInput, CreateClickupTaskInput, CreateClickupTaskResult, ExternalToolSummary, IssueChatTokenInput, ListAgentsResult, ListConnectorResourcesResult, McpServerConfig, MessageRecord, MessageRole, PublicAppBranding, PublicProfileBlock, PublicProfileTemplate, PublicTeamLanding, CreateTeamInput, UpdateTeamInput, TeamSummary, TeamDetail, TeamTheme, TeamProfileBlock, AppInstallation, TemplateConfigField, TemplateSummary, TemplateDetail, TemplateInstallResult, TenantConfigEntry, AppSelf, AppSelfConnector, AppSelfConnectors, AppSelfConnectorTools, AppSelfConnectorToolsResponse, RegisterToolInput, RegisterToolsInput, BusinessRoleEntry, RegisterToolsResult, ToolCallbackPayload, ToolCallRecord, ToolPermission, ToolPermissionMode, TokenUsage, TenantSecretEntry, UpdateAgentInput, InboxThreadMode, InboxMessageDirection, InboxMessageSource, InboxMessageType, InboxThreadCustomerProfileView, InboxThreadView, InboxMessageView, SupportKpiTotals, SupportKpiResponse, AgentAttentionLogRow, } from './types';
5
+ export type { AgentMe, AgentSummary, AppUserConnectorStatus, ApprovalCopyBundle, ChannelContext, ChatStreamChunk, ChatStreamEvent, ChatTokenRecord, ConnectorDefaultsResult, ConnectorDefaultsSource, ConnectorResourceItem, ConnectorStatus, ConnectorToolInfo, ConversationHistory, ConversationStatus, CreateAgentInput, CreateClickupTaskInput, CreateClickupTaskResult, ExternalToolSummary, IssueChatTokenInput, ListAgentsResult, ListConnectorResourcesResult, McpServerConfig, MessageRecord, MessageRole, PublicAppBranding, PublicProfileBlock, PublicProfileTemplate, PublicTeamLanding, CreateTeamInput, UpdateTeamInput, TeamSummary, TeamDetail, TeamTheme, TeamBusinessHours, TeamWeekday, TeamProfileBlock, AppInstallation, TemplateConfigField, TemplateSummary, TemplateDetail, TemplateInstallResult, TenantConfigEntry, AppSelf, AppSelfConnector, AppSelfConnectors, AppSelfConnectorTools, AppSelfConnectorToolsResponse, RegisterToolInput, RegisterToolsInput, BusinessRoleEntry, Catalog, CatalogCheckoutCta, CatalogCategory, CatalogProduct, CatalogProductPhoto, CatalogProductKind, CatalogProductStatus, CatalogPriceKind, CatalogAvailability, CatalogLockableField, CatalogProductPage, UpsertCatalogInput, CreateCatalogCategoryInput, UpdateCatalogCategoryInput, CreateCatalogProductInput, UpdateCatalogProductInput, ListCatalogProductsInput, CatalogPhotoUploadTarget, SignCatalogPhotoUploadInput, AttachCatalogPhotoInput, CatalogImportItem, CatalogImportPreview, CatalogImportApplyResult, CatalogFileMapping, CatalogFilePlan, CatalogFilePreview, CatalogFileApplyResult, CatalogFileInput, CatalogFilePreviewInput, CatalogFileApplyInput, CatalogFileErrorCode, CatalogImportSourceStatus, CatalogImportColumnMapping, CatalogImportRunResult, CatalogImportSource, CreateCatalogImportSourceInput, UpdateCatalogImportSourceInput, PreviewCatalogImportSourceInput, CatalogImportSourcePreview, RegisterToolsResult, ToolCallbackPayload, ToolCallRecord, ToolPermission, ToolPermissionMode, TokenUsage, TenantSecretEntry, UpdateAgentInput, InboxThreadMode, InboxMessageDirection, InboxMessageSource, InboxMessageType, InboxThreadCustomerProfileView, InboxThreadView, InboxMessageView, SupportKpiTotals, SupportKpiResponse, AgentAttentionLogRow, } from './types';
6
6
  export { AgentsResource } from './resources/agents';
7
7
  export { AnalyticsResource } from './resources/analytics';
8
8
  export type { GetSupportKpisInput, GetAgentAttentionLogInput, } from './resources/analytics';
@@ -18,6 +18,7 @@ export { TemplatesResource } from './resources/templates';
18
18
  export type { ListTemplatesInput } from './resources/templates';
19
19
  export { TenantConfigResource } from './resources/config';
20
20
  export { BusinessRolesResource } from './resources/business-roles';
21
+ export { CatalogResource, CatalogCategoriesResource, CatalogProductsResource, CatalogPhotosResource, CatalogImportResource, CatalogFileImportResource, CatalogSourcesResource, AgentForgeCatalogImportLimitError, CATALOG_IMPORT_MAX_ITEMS, } from './resources/catalog';
21
22
  export type { ListThreadsOptions, SendMessageInput, AssignThreadInput, UnassignThreadInput, SetThreadModeInput, CloseThreadInput, } from './resources/inbox';
22
23
  export { ProvisioningResource } from './resources/provisioning';
23
24
  export type { ProvisionedTenant, ProvisionedApp, ProvisionedTeam, } from './resources/provisioning';
package/dist/index.js CHANGED
@@ -28,7 +28,7 @@
28
28
  // const payload = af.tools.verifyCallback({ rawBody, signatureHeader, secretPlaintext });
29
29
  // await af.tools.respondToCallback({ resultUrl: payload.resultUrl, tenantId: payload.tenantId, secret, result });
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.ToolsResource = exports.TeamsResource = exports.SecretsResource = exports.ProvisioningResource = exports.BusinessRolesResource = exports.TenantConfigResource = exports.TemplatesResource = exports.InstallationsResource = exports.InboxResource = exports.ConnectorsResource = exports.ChatResource = exports.AppsResource = exports.AnalyticsResource = exports.AgentsResource = exports.verifyToolCallbackSignature = exports.signToolCallbackPayload = exports.ToolCallbackSignatureError = exports.TOOL_CALLBACK_HEADERS = exports.AgentForgeNetworkError = exports.AgentForgeNotFoundError = exports.AgentForgeAuthError = exports.AgentForgeError = exports.INSTALLED_TENANT_HEADER = exports.AgentForgeClient = void 0;
31
+ exports.ToolsResource = exports.TeamsResource = exports.SecretsResource = exports.ProvisioningResource = exports.CATALOG_IMPORT_MAX_ITEMS = exports.AgentForgeCatalogImportLimitError = exports.CatalogSourcesResource = exports.CatalogFileImportResource = exports.CatalogImportResource = exports.CatalogPhotosResource = exports.CatalogProductsResource = exports.CatalogCategoriesResource = exports.CatalogResource = exports.BusinessRolesResource = exports.TenantConfigResource = exports.TemplatesResource = exports.InstallationsResource = exports.InboxResource = exports.ConnectorsResource = exports.ChatResource = exports.AppsResource = exports.AnalyticsResource = exports.AgentsResource = exports.verifyToolCallbackSignature = exports.signToolCallbackPayload = exports.ToolCallbackSignatureError = exports.TOOL_CALLBACK_HEADERS = exports.AgentForgeNetworkError = exports.AgentForgeNotFoundError = exports.AgentForgeAuthError = exports.AgentForgeError = exports.INSTALLED_TENANT_HEADER = exports.AgentForgeClient = void 0;
32
32
  var client_1 = require("./client");
33
33
  Object.defineProperty(exports, "AgentForgeClient", { enumerable: true, get: function () { return client_1.AgentForgeClient; } });
34
34
  Object.defineProperty(exports, "INSTALLED_TENANT_HEADER", { enumerable: true, get: function () { return client_1.INSTALLED_TENANT_HEADER; } });
@@ -62,6 +62,16 @@ var config_1 = require("./resources/config");
62
62
  Object.defineProperty(exports, "TenantConfigResource", { enumerable: true, get: function () { return config_1.TenantConfigResource; } });
63
63
  var business_roles_1 = require("./resources/business-roles");
64
64
  Object.defineProperty(exports, "BusinessRolesResource", { enumerable: true, get: function () { return business_roles_1.BusinessRolesResource; } });
65
+ var catalog_1 = require("./resources/catalog");
66
+ Object.defineProperty(exports, "CatalogResource", { enumerable: true, get: function () { return catalog_1.CatalogResource; } });
67
+ Object.defineProperty(exports, "CatalogCategoriesResource", { enumerable: true, get: function () { return catalog_1.CatalogCategoriesResource; } });
68
+ Object.defineProperty(exports, "CatalogProductsResource", { enumerable: true, get: function () { return catalog_1.CatalogProductsResource; } });
69
+ Object.defineProperty(exports, "CatalogPhotosResource", { enumerable: true, get: function () { return catalog_1.CatalogPhotosResource; } });
70
+ Object.defineProperty(exports, "CatalogImportResource", { enumerable: true, get: function () { return catalog_1.CatalogImportResource; } });
71
+ Object.defineProperty(exports, "CatalogFileImportResource", { enumerable: true, get: function () { return catalog_1.CatalogFileImportResource; } });
72
+ Object.defineProperty(exports, "CatalogSourcesResource", { enumerable: true, get: function () { return catalog_1.CatalogSourcesResource; } });
73
+ Object.defineProperty(exports, "AgentForgeCatalogImportLimitError", { enumerable: true, get: function () { return catalog_1.AgentForgeCatalogImportLimitError; } });
74
+ Object.defineProperty(exports, "CATALOG_IMPORT_MAX_ITEMS", { enumerable: true, get: function () { return catalog_1.CATALOG_IMPORT_MAX_ITEMS; } });
65
75
  var provisioning_1 = require("./resources/provisioning");
66
76
  Object.defineProperty(exports, "ProvisioningResource", { enumerable: true, get: function () { return provisioning_1.ProvisioningResource; } });
67
77
  var secrets_1 = require("./resources/secrets");
@@ -0,0 +1,120 @@
1
+ import type { AgentForgeClient } from '../client';
2
+ import { AgentForgeError } from '../errors';
3
+ import type { AttachCatalogPhotoInput, Catalog, CatalogCategory, CatalogFileApplyInput, CatalogFileApplyResult, CatalogFilePreview, CatalogFilePreviewInput, CatalogImportApplyResult, CatalogImportItem, CatalogImportPreview, CatalogImportSource, CatalogImportSourcePreview, CatalogImportRunResult, CatalogPhotoUploadTarget, CatalogProduct, CatalogProductPage, CreateCatalogCategoryInput, CreateCatalogImportSourceInput, CreateCatalogProductInput, ListCatalogProductsInput, PreviewCatalogImportSourceInput, SignCatalogPhotoUploadInput, UpdateCatalogCategoryInput, UpdateCatalogImportSourceInput, UpdateCatalogProductInput, UpsertCatalogInput } from '../types';
4
+ /** Max structured items per `import.preview/apply` call (platform cap). */
5
+ export declare const CATALOG_IMPORT_MAX_ITEMS = 200;
6
+ /** Thrown client-side, before any request, when `items` exceeds the cap. */
7
+ export declare class AgentForgeCatalogImportLimitError extends AgentForgeError {
8
+ readonly count: number;
9
+ constructor(count: number);
10
+ }
11
+ export declare class CatalogCategoriesResource {
12
+ private readonly client;
13
+ constructor(client: AgentForgeClient);
14
+ /** `GET /categories` — ordered by `sortOrder`. */
15
+ list(): Promise<CatalogCategory[]>;
16
+ /** `POST /categories` */
17
+ create(input: CreateCatalogCategoryInput): Promise<CatalogCategory>;
18
+ /** `PATCH /categories/:id` */
19
+ update(categoryId: string, input: UpdateCatalogCategoryInput): Promise<CatalogCategory>;
20
+ /** `DELETE /categories/:id` */
21
+ delete(categoryId: string): Promise<void>;
22
+ /** `PATCH /categories/reorder` — `orderedIds` must be exactly the current set. */
23
+ reorder(orderedIds: string[]): Promise<CatalogCategory[]>;
24
+ }
25
+ export declare class CatalogPhotosResource {
26
+ private readonly client;
27
+ constructor(client: AgentForgeClient);
28
+ private path;
29
+ /** `POST …/photos/sign-upload` — signed direct-upload target. PUT the bytes
30
+ * to `uploadUrl`, then `attach({ url: publicUrl, key })`. */
31
+ signUpload(productId: string, input: SignCatalogPhotoUploadInput): Promise<CatalogPhotoUploadTarget>;
32
+ /** `POST …/photos` — persist an uploaded (or external) photo. The first photo becomes the cover. */
33
+ attach(productId: string, input: AttachCatalogPhotoInput): Promise<CatalogProduct>;
34
+ /** `DELETE …/photos` — remove by URL (also deletes the stored object). */
35
+ remove(productId: string, url: string): Promise<CatalogProduct>;
36
+ /** `PATCH …/photos/reorder` — send the full ordered URL list; omitted URLs are dropped. */
37
+ reorder(productId: string, orderedUrls: string[]): Promise<CatalogProduct>;
38
+ /** `PATCH …/photos/cover` */
39
+ setCover(productId: string, url: string): Promise<CatalogProduct>;
40
+ }
41
+ export declare class CatalogProductsResource {
42
+ private readonly client;
43
+ readonly photos: CatalogPhotosResource;
44
+ constructor(client: AgentForgeClient);
45
+ /** `GET /products` — includes drafts/archived (owner view). Paginated. */
46
+ list(input?: ListCatalogProductsInput): Promise<CatalogProductPage>;
47
+ /** `GET /products/:id` — 404 → `AgentForgeNotFoundError`. */
48
+ get(productId: string): Promise<CatalogProduct>;
49
+ /** `POST /products` — needs a catalog (`catalog.upsert`). `priceCents` is
50
+ * required unless `priceKind: 'on_request'` (else `PRICE_REQUIRED`). */
51
+ create(input: CreateCatalogProductInput): Promise<CatalogProduct>;
52
+ /** `PATCH /products/:id` */
53
+ update(productId: string, input: UpdateCatalogProductInput): Promise<CatalogProduct>;
54
+ /** `DELETE /products/:id` */
55
+ delete(productId: string): Promise<void>;
56
+ /** `PATCH /products/reorder` — reorder inside ONE scope: a category, or
57
+ * `categoryId: null` for the uncategorized products. `orderedIds` must be exactly that set. */
58
+ reorder(input: {
59
+ categoryId: string | null;
60
+ orderedIds: string[];
61
+ }): Promise<CatalogProduct[]>;
62
+ }
63
+ export declare class CatalogFileImportResource {
64
+ private readonly client;
65
+ constructor(client: AgentForgeClient);
66
+ private post;
67
+ /** `POST /import/file/preview` (multipart) — parse an .xlsx/.csv (≤5 MB, ≤2000 rows)
68
+ * and get headers, sample rows and a suggested mapping. With `mapping` it also
69
+ * returns a `plan`. Errors carry `code` (`FILE_*`, `INVALID_MAPPING`, …). */
70
+ preview(input: CatalogFilePreviewInput): Promise<CatalogFilePreview>;
71
+ /** `POST /import/file/apply` (multipart) — import the file using `mapping`
72
+ * (field → exact header). Needs a catalog. */
73
+ apply(input: CatalogFileApplyInput): Promise<CatalogFileApplyResult>;
74
+ }
75
+ export declare class CatalogImportResource {
76
+ private readonly client;
77
+ readonly file: CatalogFileImportResource;
78
+ constructor(client: AgentForgeClient);
79
+ /** `POST /import/preview` — validate structured items WITHOUT writing. Max 200
80
+ * (throws `AgentForgeCatalogImportLimitError` above that, before any request). */
81
+ preview(items: CatalogImportItem[]): Promise<CatalogImportPreview>;
82
+ /** `POST /import/apply` — create-only, idempotent per slug. Max 200 per call. */
83
+ apply(items: CatalogImportItem[]): Promise<CatalogImportApplyResult>;
84
+ /** `GET /import/template.xlsx` — the downloadable template (xlsx bytes). */
85
+ template(): Promise<ArrayBuffer>;
86
+ }
87
+ export declare class CatalogSourcesResource {
88
+ private readonly client;
89
+ constructor(client: AgentForgeClient);
90
+ /** `GET /import-sources` */
91
+ list(): Promise<CatalogImportSource[]>;
92
+ /** `POST /import-sources` — Google Sheets or Shopify source. */
93
+ create(input: CreateCatalogImportSourceInput): Promise<CatalogImportSource>;
94
+ /** `PATCH /import-sources/:id` */
95
+ update(sourceId: string, input: UpdateCatalogImportSourceInput): Promise<CatalogImportSource>;
96
+ /** `DELETE /import-sources/:id` */
97
+ delete(sourceId: string): Promise<void>;
98
+ /** `POST /import-sources/preview` — sample a Google Sheet (headers, rows,
99
+ * suggested mapping) before saving a source. Needs a connected Google grant
100
+ * (`NO_GOOGLE_GRANT` otherwise). */
101
+ preview(input: PreviewCatalogImportSourceInput): Promise<CatalogImportSourcePreview>;
102
+ /** `POST /import-sources/:id/run` — sync now. Always resolves with `lastResult`;
103
+ * run-level failures are in `lastResult.error`. */
104
+ run(sourceId: string): Promise<{
105
+ lastResult: CatalogImportRunResult;
106
+ }>;
107
+ }
108
+ export declare class CatalogResource {
109
+ private readonly client;
110
+ readonly categories: CatalogCategoriesResource;
111
+ readonly products: CatalogProductsResource;
112
+ readonly import: CatalogImportResource;
113
+ readonly sources: CatalogSourcesResource;
114
+ constructor(client: AgentForgeClient);
115
+ /** `GET /api/v1/catalog` — the tenant's catalog, or `null` when it has none yet
116
+ * (404 `CATALOG_NOT_FOUND`). Other 404s still throw. */
117
+ get(): Promise<Catalog | null>;
118
+ /** `PUT /api/v1/catalog` — ensure-or-update: creates the catalog if missing, then applies the settings. */
119
+ upsert(input?: UpsertCatalogInput): Promise<Catalog>;
120
+ }
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ // catalog resource — the tenant's catalog for API-key / App-secret callers
3
+ // (AGF-CATALOG-ONB), `/api/v1/catalog/*`. A host App (PoodleDeck…) manages a
4
+ // business's products, services and categories without hand-rolled fetch.
5
+ //
6
+ // const biz = af.forTenant(installation.tenantId);
7
+ // await biz.catalog.upsert({ currency: 'COP' });
8
+ // await biz.catalog.products.create({ title: 'Café', priceCents: 450000 });
9
+ //
10
+ // The tenant is always the one the client acts in (`forTenant` → `x-af-tenant`,
11
+ // or the `ak_live_` key's own); it is never a parameter. Agent-scoped keys and
12
+ // chat tokens are refused by the platform — this resource always sends the
13
+ // tenant credential (`forceApiKey`).
14
+ //
15
+ // Failures throw the SDK's typed errors; `error.code` carries the platform's
16
+ // machine-readable code (`CATALOG_NOT_FOUND`, `FILE_EMPTY_FILE`,
17
+ // `INVALID_MAPPING`, `TOO_MANY_ITEMS`, …).
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.CatalogResource = exports.CatalogSourcesResource = exports.CatalogImportResource = exports.CatalogFileImportResource = exports.CatalogProductsResource = exports.CatalogPhotosResource = exports.CatalogCategoriesResource = exports.AgentForgeCatalogImportLimitError = exports.CATALOG_IMPORT_MAX_ITEMS = void 0;
20
+ const errors_1 = require("../errors");
21
+ const BASE = '/api/v1/catalog';
22
+ const TENANT_AUTH = { forceApiKey: true };
23
+ /** Max structured items per `import.preview/apply` call (platform cap). */
24
+ exports.CATALOG_IMPORT_MAX_ITEMS = 200;
25
+ /** Thrown client-side, before any request, when `items` exceeds the cap. */
26
+ class AgentForgeCatalogImportLimitError extends errors_1.AgentForgeError {
27
+ constructor(count) {
28
+ super(400, `catalog.import accepts at most ${exports.CATALOG_IMPORT_MAX_ITEMS} items per call (got ${count}). Split into chunks.`, undefined, 'TOO_MANY_ITEMS');
29
+ this.name = 'AgentForgeCatalogImportLimitError';
30
+ this.count = count;
31
+ }
32
+ }
33
+ exports.AgentForgeCatalogImportLimitError = AgentForgeCatalogImportLimitError;
34
+ const seg = encodeURIComponent;
35
+ function guardItems(items) {
36
+ if (items.length > exports.CATALOG_IMPORT_MAX_ITEMS)
37
+ throw new AgentForgeCatalogImportLimitError(items.length);
38
+ }
39
+ function toBlob(file) {
40
+ if (file instanceof Blob)
41
+ return file;
42
+ // Copy into a fresh ArrayBuffer-backed view so Blob never sees a SharedArrayBuffer.
43
+ const bytes = file instanceof Uint8Array ? file : new Uint8Array(file);
44
+ return new Blob([new Uint8Array(bytes)]);
45
+ }
46
+ function fileForm(input) {
47
+ const form = new FormData();
48
+ form.append('file', toBlob(input.file), input.filename);
49
+ if (input.mapping !== undefined)
50
+ form.append('mapping', JSON.stringify(input.mapping));
51
+ if (input.kind !== undefined)
52
+ form.append('kind', input.kind);
53
+ if (input.currency !== undefined)
54
+ form.append('currency', input.currency);
55
+ return form;
56
+ }
57
+ class CatalogCategoriesResource {
58
+ constructor(client) {
59
+ this.client = client;
60
+ }
61
+ /** `GET /categories` — ordered by `sortOrder`. */
62
+ async list() {
63
+ return this.client.request('GET', `${BASE}/categories`, undefined, TENANT_AUTH);
64
+ }
65
+ /** `POST /categories` */
66
+ async create(input) {
67
+ return this.client.request('POST', `${BASE}/categories`, input, TENANT_AUTH);
68
+ }
69
+ /** `PATCH /categories/:id` */
70
+ async update(categoryId, input) {
71
+ return this.client.request('PATCH', `${BASE}/categories/${seg(categoryId)}`, input, TENANT_AUTH);
72
+ }
73
+ /** `DELETE /categories/:id` */
74
+ async delete(categoryId) {
75
+ await this.client.request('DELETE', `${BASE}/categories/${seg(categoryId)}`, undefined, TENANT_AUTH);
76
+ }
77
+ /** `PATCH /categories/reorder` — `orderedIds` must be exactly the current set. */
78
+ async reorder(orderedIds) {
79
+ return this.client.request('PATCH', `${BASE}/categories/reorder`, { orderedIds }, TENANT_AUTH);
80
+ }
81
+ }
82
+ exports.CatalogCategoriesResource = CatalogCategoriesResource;
83
+ class CatalogPhotosResource {
84
+ constructor(client) {
85
+ this.client = client;
86
+ }
87
+ path(productId, tail = '') {
88
+ return `${BASE}/products/${seg(productId)}/photos${tail}`;
89
+ }
90
+ /** `POST …/photos/sign-upload` — signed direct-upload target. PUT the bytes
91
+ * to `uploadUrl`, then `attach({ url: publicUrl, key })`. */
92
+ async signUpload(productId, input) {
93
+ return this.client.request('POST', this.path(productId, '/sign-upload'), input, TENANT_AUTH);
94
+ }
95
+ /** `POST …/photos` — persist an uploaded (or external) photo. The first photo becomes the cover. */
96
+ async attach(productId, input) {
97
+ return this.client.request('POST', this.path(productId), input, TENANT_AUTH);
98
+ }
99
+ /** `DELETE …/photos` — remove by URL (also deletes the stored object). */
100
+ async remove(productId, url) {
101
+ return this.client.request('DELETE', this.path(productId), { url }, TENANT_AUTH);
102
+ }
103
+ /** `PATCH …/photos/reorder` — send the full ordered URL list; omitted URLs are dropped. */
104
+ async reorder(productId, orderedUrls) {
105
+ return this.client.request('PATCH', this.path(productId, '/reorder'), { orderedUrls }, TENANT_AUTH);
106
+ }
107
+ /** `PATCH …/photos/cover` */
108
+ async setCover(productId, url) {
109
+ return this.client.request('PATCH', this.path(productId, '/cover'), { url }, TENANT_AUTH);
110
+ }
111
+ }
112
+ exports.CatalogPhotosResource = CatalogPhotosResource;
113
+ class CatalogProductsResource {
114
+ constructor(client) {
115
+ this.client = client;
116
+ this.photos = new CatalogPhotosResource(client);
117
+ }
118
+ /** `GET /products` — includes drafts/archived (owner view). Paginated. */
119
+ async list(input = {}) {
120
+ const qs = new URLSearchParams();
121
+ if (input.q)
122
+ qs.set('q', input.q);
123
+ if (input.categoryId)
124
+ qs.set('categoryId', input.categoryId);
125
+ if (input.onlyAvailable)
126
+ qs.set('onlyAvailable', 'true');
127
+ if (input.kind)
128
+ qs.set('kind', input.kind);
129
+ if (input.page !== undefined)
130
+ qs.set('page', String(input.page));
131
+ if (input.pageSize !== undefined)
132
+ qs.set('pageSize', String(input.pageSize));
133
+ const q = qs.toString();
134
+ return this.client.request('GET', `${BASE}/products${q ? `?${q}` : ''}`, undefined, TENANT_AUTH);
135
+ }
136
+ /** `GET /products/:id` — 404 → `AgentForgeNotFoundError`. */
137
+ async get(productId) {
138
+ return this.client.request('GET', `${BASE}/products/${seg(productId)}`, undefined, TENANT_AUTH);
139
+ }
140
+ /** `POST /products` — needs a catalog (`catalog.upsert`). `priceCents` is
141
+ * required unless `priceKind: 'on_request'` (else `PRICE_REQUIRED`). */
142
+ async create(input) {
143
+ return this.client.request('POST', `${BASE}/products`, input, TENANT_AUTH);
144
+ }
145
+ /** `PATCH /products/:id` */
146
+ async update(productId, input) {
147
+ return this.client.request('PATCH', `${BASE}/products/${seg(productId)}`, input, TENANT_AUTH);
148
+ }
149
+ /** `DELETE /products/:id` */
150
+ async delete(productId) {
151
+ await this.client.request('DELETE', `${BASE}/products/${seg(productId)}`, undefined, TENANT_AUTH);
152
+ }
153
+ /** `PATCH /products/reorder` — reorder inside ONE scope: a category, or
154
+ * `categoryId: null` for the uncategorized products. `orderedIds` must be exactly that set. */
155
+ async reorder(input) {
156
+ const qs = `?categoryId=${input.categoryId === null ? 'null' : seg(input.categoryId)}`;
157
+ return this.client.request('PATCH', `${BASE}/products/reorder${qs}`, { orderedIds: input.orderedIds }, TENANT_AUTH);
158
+ }
159
+ }
160
+ exports.CatalogProductsResource = CatalogProductsResource;
161
+ class CatalogFileImportResource {
162
+ constructor(client) {
163
+ this.client = client;
164
+ }
165
+ async post(path, form) {
166
+ const res = await this.client.requestRaw('POST', path, { ...TENANT_AUTH, formData: form });
167
+ return (await res.json());
168
+ }
169
+ /** `POST /import/file/preview` (multipart) — parse an .xlsx/.csv (≤5 MB, ≤2000 rows)
170
+ * and get headers, sample rows and a suggested mapping. With `mapping` it also
171
+ * returns a `plan`. Errors carry `code` (`FILE_*`, `INVALID_MAPPING`, …). */
172
+ async preview(input) {
173
+ return this.post(`${BASE}/import/file/preview`, fileForm(input));
174
+ }
175
+ /** `POST /import/file/apply` (multipart) — import the file using `mapping`
176
+ * (field → exact header). Needs a catalog. */
177
+ async apply(input) {
178
+ return this.post(`${BASE}/import/file/apply`, fileForm(input));
179
+ }
180
+ }
181
+ exports.CatalogFileImportResource = CatalogFileImportResource;
182
+ class CatalogImportResource {
183
+ constructor(client) {
184
+ this.client = client;
185
+ this.file = new CatalogFileImportResource(client);
186
+ }
187
+ /** `POST /import/preview` — validate structured items WITHOUT writing. Max 200
188
+ * (throws `AgentForgeCatalogImportLimitError` above that, before any request). */
189
+ async preview(items) {
190
+ guardItems(items);
191
+ return this.client.request('POST', `${BASE}/import/preview`, { items }, TENANT_AUTH);
192
+ }
193
+ /** `POST /import/apply` — create-only, idempotent per slug. Max 200 per call. */
194
+ async apply(items) {
195
+ guardItems(items);
196
+ return this.client.request('POST', `${BASE}/import/apply`, { items }, TENANT_AUTH);
197
+ }
198
+ /** `GET /import/template.xlsx` — the downloadable template (xlsx bytes). */
199
+ async template() {
200
+ const res = await this.client.requestRaw('GET', `${BASE}/import/template.xlsx`, TENANT_AUTH);
201
+ return res.arrayBuffer();
202
+ }
203
+ }
204
+ exports.CatalogImportResource = CatalogImportResource;
205
+ class CatalogSourcesResource {
206
+ constructor(client) {
207
+ this.client = client;
208
+ }
209
+ /** `GET /import-sources` */
210
+ async list() {
211
+ return this.client.request('GET', `${BASE}/import-sources`, undefined, TENANT_AUTH);
212
+ }
213
+ /** `POST /import-sources` — Google Sheets or Shopify source. */
214
+ async create(input) {
215
+ return this.client.request('POST', `${BASE}/import-sources`, input, TENANT_AUTH);
216
+ }
217
+ /** `PATCH /import-sources/:id` */
218
+ async update(sourceId, input) {
219
+ return this.client.request('PATCH', `${BASE}/import-sources/${seg(sourceId)}`, input, TENANT_AUTH);
220
+ }
221
+ /** `DELETE /import-sources/:id` */
222
+ async delete(sourceId) {
223
+ await this.client.request('DELETE', `${BASE}/import-sources/${seg(sourceId)}`, undefined, TENANT_AUTH);
224
+ }
225
+ /** `POST /import-sources/preview` — sample a Google Sheet (headers, rows,
226
+ * suggested mapping) before saving a source. Needs a connected Google grant
227
+ * (`NO_GOOGLE_GRANT` otherwise). */
228
+ async preview(input) {
229
+ return this.client.request('POST', `${BASE}/import-sources/preview`, input, TENANT_AUTH);
230
+ }
231
+ /** `POST /import-sources/:id/run` — sync now. Always resolves with `lastResult`;
232
+ * run-level failures are in `lastResult.error`. */
233
+ async run(sourceId) {
234
+ return this.client.request('POST', `${BASE}/import-sources/${seg(sourceId)}/run`, undefined, TENANT_AUTH);
235
+ }
236
+ }
237
+ exports.CatalogSourcesResource = CatalogSourcesResource;
238
+ class CatalogResource {
239
+ constructor(client) {
240
+ this.client = client;
241
+ this.categories = new CatalogCategoriesResource(client);
242
+ this.products = new CatalogProductsResource(client);
243
+ this.import = new CatalogImportResource(client);
244
+ this.sources = new CatalogSourcesResource(client);
245
+ }
246
+ /** `GET /api/v1/catalog` — the tenant's catalog, or `null` when it has none yet
247
+ * (404 `CATALOG_NOT_FOUND`). Other 404s still throw. */
248
+ async get() {
249
+ try {
250
+ return await this.client.request('GET', BASE, undefined, TENANT_AUTH);
251
+ }
252
+ catch (e) {
253
+ if (e instanceof errors_1.AgentForgeNotFoundError && e.code === 'CATALOG_NOT_FOUND')
254
+ return null;
255
+ throw e;
256
+ }
257
+ }
258
+ /** `PUT /api/v1/catalog` — ensure-or-update: creates the catalog if missing, then applies the settings. */
259
+ async upsert(input = {}) {
260
+ return this.client.request('PUT', BASE, input, TENANT_AUTH);
261
+ }
262
+ }
263
+ exports.CatalogResource = CatalogResource;
package/dist/types.d.ts CHANGED
@@ -700,7 +700,26 @@ export interface UpdateTeamInput {
700
700
  /** The page's blocks in render order (`enabled: false` hides one). Links
701
701
  * must be http(s), mailto:, tel: or sms:. `null` or `[]` clears them. */
702
702
  profileBlocks?: TeamProfileBlock[] | null;
703
+ /** When the team takes human escalations (and what the agent tells
704
+ * customers about being open). Normalized by the platform: windows
705
+ * sorted, overlapping ones merged. `null` clears it (always open). An
706
+ * empty `schedule` is a 400 — send `null` instead. */
707
+ businessHours?: TeamBusinessHours | null;
703
708
  }
709
+ /** A team's weekly opening hours (AGF-HOURS). */
710
+ export interface TeamBusinessHours {
711
+ /** IANA timezone, e.g. `America/Bogota`. */
712
+ timezone: string;
713
+ /** Open windows, `"HH:mm"` 00:00–23:59, `to` after `from`; a day may
714
+ * have several (split shift); a day with none is closed. Overnight
715
+ * windows go as two entries on adjacent days. */
716
+ schedule: Array<{
717
+ day: TeamWeekday;
718
+ from: string;
719
+ to: string;
720
+ }>;
721
+ }
722
+ export type TeamWeekday = 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat' | 'sun';
704
723
  /** A team's public-page theme (`af_teams.theme`). Colors are hex strings. */
705
724
  export interface TeamTheme {
706
725
  logoUrl?: string;
@@ -783,6 +802,7 @@ export interface TeamDetail {
783
802
  id: string;
784
803
  enabled: boolean;
785
804
  }> | null;
805
+ businessHours?: TeamBusinessHours | null;
786
806
  };
787
807
  members: Array<{
788
808
  agentId: string;
@@ -865,4 +885,351 @@ export interface BusinessRoleEntry {
865
885
  color: string;
866
886
  icon: string | null;
867
887
  }
888
+ /** `product` = physical goods; `service` = offering with no stock. */
889
+ export type CatalogProductKind = 'product' | 'service';
890
+ /** Lifecycle. Only `active` is visible to the public catalog and the client
891
+ * agent; `draft` and `archived` are owner-only. */
892
+ export type CatalogProductStatus = 'draft' | 'active' | 'archived';
893
+ /** How `priceCents` reads. `on_request` = no published price (null). */
894
+ export type CatalogPriceKind = 'fixed' | 'from' | 'per_unit' | 'on_request';
895
+ /** Reported stock level for products without a numeric `stock`. */
896
+ export type CatalogAvailability = 'in_stock' | 'low' | 'out';
897
+ export interface CatalogCheckoutCta {
898
+ type: 'wa' | 'custom' | 'none';
899
+ /** Required for `wa` and `custom` (the target URL); must be omitted for `none`. */
900
+ value?: string;
901
+ }
902
+ export interface Catalog {
903
+ id: string;
904
+ tenantId: string;
905
+ currency: string;
906
+ checkoutCta: CatalogCheckoutCta;
907
+ isActive: boolean;
908
+ /** AI-curation settings (read-only here; managed from the dashboard). */
909
+ aiCuration?: {
910
+ mode: 'off' | 'suggest' | 'auto';
911
+ origins?: Partial<Record<'prompt' | 'conversation' | 'owner' | 'sales' | 'sources', boolean>>;
912
+ autoApplyMinConfidence?: number;
913
+ dailyTokenBudget?: number;
914
+ };
915
+ createdAt: string;
916
+ updatedAt: string;
917
+ }
918
+ /** `PUT /api/v1/catalog` — ensure-or-update. */
919
+ export interface UpsertCatalogInput {
920
+ /** 3-letter currency code. */
921
+ currency?: string;
922
+ checkoutCta?: CatalogCheckoutCta;
923
+ isActive?: boolean;
924
+ }
925
+ export interface CatalogCategory {
926
+ id: string;
927
+ catalogId: string;
928
+ name: string;
929
+ slug: string;
930
+ sortOrder: number;
931
+ createdAt: string;
932
+ updatedAt: string;
933
+ }
934
+ export interface CreateCatalogCategoryInput {
935
+ name: string;
936
+ /** Derived from `name` when omitted. */
937
+ slug?: string;
938
+ }
939
+ export interface UpdateCatalogCategoryInput {
940
+ name?: string;
941
+ slug?: string;
942
+ }
943
+ export interface CatalogProductPhoto {
944
+ url: string;
945
+ sortOrder: number;
946
+ isCover: boolean;
947
+ /** Storage key backing `url` when the platform's upload service wrote it. */
948
+ key?: string;
949
+ /** Source URL the photo was copied from (imports/syncs). */
950
+ sourceUrl?: string;
951
+ }
952
+ export type CatalogLockableField = 'title' | 'description' | 'priceCents' | 'priceKind' | 'unit' | 'categoryId' | 'kind' | 'aliases' | 'attributes' | 'availability' | 'stock' | 'isAvailable' | 'photos';
953
+ export interface CatalogProduct {
954
+ id: string;
955
+ catalogId: string;
956
+ categoryId?: string | null;
957
+ slug: string;
958
+ title: string;
959
+ description?: string;
960
+ /** `null` only when `priceKind === 'on_request'`. */
961
+ priceCents: number | null;
962
+ currency: string;
963
+ /** `null`/absent = not tracked. */
964
+ stock?: number | null;
965
+ /** `stock` minus active reservations, floored at 0; `null` when stock is untracked. */
966
+ effectiveStock?: number | null;
967
+ photos: CatalogProductPhoto[];
968
+ isAvailable: boolean;
969
+ sortOrder: number;
970
+ origin?: string;
971
+ externalId?: string | null;
972
+ kind: CatalogProductKind;
973
+ status: CatalogProductStatus;
974
+ priceKind: CatalogPriceKind;
975
+ unit?: string | null;
976
+ aliases: string[];
977
+ attributes: Record<string, unknown>;
978
+ availability?: CatalogAvailability | null;
979
+ availabilityAt?: string | null;
980
+ fieldProvenance: Record<string, {
981
+ origin: string;
982
+ signalId?: string;
983
+ at: string;
984
+ }>;
985
+ lockedFields: CatalogLockableField[];
986
+ lastSoldAt?: string | null;
987
+ demandCount: number;
988
+ createdAt: string;
989
+ updatedAt: string;
990
+ }
991
+ export interface CreateCatalogProductInput {
992
+ title: string;
993
+ slug?: string;
994
+ description?: string;
995
+ /** Integer cents. Required unless `priceKind` is `'on_request'` (then null/omitted). */
996
+ priceCents?: number | null;
997
+ currency?: string;
998
+ stock?: number | null;
999
+ categoryId?: string | null;
1000
+ isAvailable?: boolean;
1001
+ kind?: CatalogProductKind;
1002
+ status?: CatalogProductStatus;
1003
+ priceKind?: CatalogPriceKind;
1004
+ /** Max 32 chars (kg, hour, load…). */
1005
+ unit?: string | null;
1006
+ /** Max 30 aliases, 80 chars each. */
1007
+ aliases?: string[];
1008
+ attributes?: Record<string, unknown>;
1009
+ availability?: CatalogAvailability | null;
1010
+ lockedFields?: CatalogLockableField[];
1011
+ }
1012
+ export interface UpdateCatalogProductInput extends Partial<CreateCatalogProductInput> {
1013
+ sortOrder?: number;
1014
+ }
1015
+ export interface ListCatalogProductsInput {
1016
+ /** Free-text search. */
1017
+ q?: string;
1018
+ categoryId?: string;
1019
+ onlyAvailable?: boolean;
1020
+ kind?: CatalogProductKind;
1021
+ /** 1-based. Default 1. */
1022
+ page?: number;
1023
+ /** Default 20, max 100 (server-capped). */
1024
+ pageSize?: number;
1025
+ }
1026
+ export interface CatalogProductPage {
1027
+ items: CatalogProduct[];
1028
+ total: number;
1029
+ page: number;
1030
+ pageSize: number;
1031
+ }
1032
+ /** `POST …/photos/sign-upload` result: PUT the bytes to `uploadUrl`, then
1033
+ * `photos.attach({ url: publicUrl, key })`. */
1034
+ export interface CatalogPhotoUploadTarget {
1035
+ uploadUrl: string;
1036
+ publicUrl: string;
1037
+ key: string;
1038
+ expiresInSeconds: number;
1039
+ }
1040
+ export interface SignCatalogPhotoUploadInput {
1041
+ /** image/jpeg, image/png, image/webp… (server whitelist). */
1042
+ contentType: string;
1043
+ contentLength?: number;
1044
+ }
1045
+ export interface AttachCatalogPhotoInput {
1046
+ url: string;
1047
+ isCover?: boolean;
1048
+ /** The `key` returned by `signUpload` (lets the platform reclaim the object on removal). */
1049
+ key?: string;
1050
+ }
1051
+ /** One structured item for `catalog.import.preview/apply` (max 200 per call). */
1052
+ export interface CatalogImportItem {
1053
+ title: string;
1054
+ /** Positive integer cents. Omit only with `priceKind: 'on_request'`. */
1055
+ priceCents?: number | null;
1056
+ priceKind?: CatalogPriceKind;
1057
+ stock?: number | null;
1058
+ /** Category NAME; created when missing. */
1059
+ category?: string;
1060
+ description?: string;
1061
+ kind?: CatalogProductKind;
1062
+ }
1063
+ export interface CatalogImportPreview {
1064
+ categoriesToCreate: Array<{
1065
+ name: string;
1066
+ slug: string;
1067
+ }>;
1068
+ categoriesExisting: Array<{
1069
+ name: string;
1070
+ slug: string;
1071
+ }>;
1072
+ productsToCreate: number;
1073
+ warnings: string[];
1074
+ }
1075
+ export interface CatalogImportApplyResult {
1076
+ categoriesCreated: Array<{
1077
+ name: string;
1078
+ slug: string;
1079
+ }>;
1080
+ productsCreated: Array<{
1081
+ slug: string;
1082
+ title: string;
1083
+ }>;
1084
+ updated: number;
1085
+ skipped: Array<{
1086
+ title: string;
1087
+ reason: string;
1088
+ }>;
1089
+ warnings: string[];
1090
+ }
1091
+ /** File → catalog field mapping. Every value is an EXACT column header of the file. */
1092
+ export interface CatalogFileMapping {
1093
+ title?: string;
1094
+ priceCents?: string;
1095
+ category?: string;
1096
+ stock?: string;
1097
+ externalId?: string;
1098
+ description?: string;
1099
+ image?: string;
1100
+ /** The template's "tipo" column (product | service). */
1101
+ kind?: string;
1102
+ }
1103
+ export interface CatalogFilePlan {
1104
+ willCreate: number;
1105
+ willUpdate: number;
1106
+ unchanged: number;
1107
+ skipped: number;
1108
+ categoriesToCreate: string[];
1109
+ }
1110
+ export interface CatalogFilePreview {
1111
+ headers: string[];
1112
+ sampleRows: string[][];
1113
+ rowCount: number;
1114
+ suggestedMapping: CatalogFileMapping;
1115
+ confidence?: 'high' | 'medium' | 'low';
1116
+ notes?: string;
1117
+ /** Present only when a `mapping` was supplied AND the tenant has a catalog. */
1118
+ plan?: CatalogFilePlan;
1119
+ warnings?: string[];
1120
+ }
1121
+ export interface CatalogFileApplyResult {
1122
+ created: number;
1123
+ updated: number;
1124
+ skipped: number;
1125
+ unchanged: number;
1126
+ categoriesCreated: string[];
1127
+ photosImported: number;
1128
+ warnings: string[];
1129
+ }
1130
+ /** Binary file accepted by the file-import calls. */
1131
+ export type CatalogFileInput = Blob | ArrayBuffer | Uint8Array;
1132
+ export interface CatalogFilePreviewInput {
1133
+ file: CatalogFileInput;
1134
+ /** Used for type detection: must end in `.xlsx` or `.csv`. */
1135
+ filename: string;
1136
+ /** Omit to get `suggestedMapping` only; supply it to also get a `plan`. */
1137
+ mapping?: CatalogFileMapping;
1138
+ /** Default `kind` for rows without a "tipo" cell. */
1139
+ kind?: CatalogProductKind;
1140
+ /** 3-letter code; price-format hint. */
1141
+ currency?: string;
1142
+ }
1143
+ export interface CatalogFileApplyInput extends Omit<CatalogFilePreviewInput, 'mapping'> {
1144
+ mapping: CatalogFileMapping;
1145
+ }
1146
+ /** Error codes of the file import (`error.code`). */
1147
+ export type CatalogFileErrorCode = 'FILE_MISSING_FILE' | 'FILE_UNSUPPORTED_TYPE' | 'FILE_FILE_TOO_LARGE' | 'FILE_CORRUPT_FILE' | 'FILE_EMPTY_FILE' | 'FILE_TOO_MANY_ROWS' | 'FILE_TOO_MANY_COLUMNS' | 'INVALID_MAPPING' | 'INVALID_KIND' | 'INVALID_CURRENCY';
1148
+ export type CatalogImportSourceStatus = 'active' | 'paused' | 'error';
1149
+ /** Column mapping stored on an import source (Sheets header → field). */
1150
+ export interface CatalogImportColumnMapping {
1151
+ title?: string;
1152
+ priceCents?: string;
1153
+ category?: string;
1154
+ stock?: string;
1155
+ externalId?: string;
1156
+ description?: string;
1157
+ image?: string;
1158
+ }
1159
+ export interface CatalogImportRunResult {
1160
+ created: number;
1161
+ updated: number;
1162
+ unavailable: number;
1163
+ skipped: number;
1164
+ warnings?: string[];
1165
+ error?: string;
1166
+ mappedRowCount?: number;
1167
+ previousCount?: number;
1168
+ }
1169
+ export interface CatalogImportSource {
1170
+ id: string;
1171
+ tenantId: string;
1172
+ /** `google-sheets` | `shopify`. */
1173
+ connectorId: string;
1174
+ spreadsheetId?: string | null;
1175
+ sheetTab?: string | null;
1176
+ range?: string | null;
1177
+ columnMapping: CatalogImportColumnMapping;
1178
+ /** Per-connector extras, e.g. `{ shop: 'acme.myshopify.com' }`. */
1179
+ config: {
1180
+ shop?: string;
1181
+ };
1182
+ currency?: string | null;
1183
+ /** Cron string; null = manual only. */
1184
+ schedule?: string | null;
1185
+ timezone: string;
1186
+ status: CatalogImportSourceStatus;
1187
+ lastRunAt?: string | null;
1188
+ lastResult?: CatalogImportRunResult | null;
1189
+ createdAt: string;
1190
+ updatedAt: string;
1191
+ }
1192
+ export interface CreateCatalogImportSourceInput {
1193
+ connectorId: string;
1194
+ /** Required for `google-sheets`. */
1195
+ spreadsheetId?: string;
1196
+ sheetTab?: string;
1197
+ /** A1 range, e.g. "Menu!A1:E999". Required for `google-sheets`. */
1198
+ range?: string;
1199
+ columnMapping?: CatalogImportColumnMapping;
1200
+ config?: {
1201
+ shop?: string;
1202
+ };
1203
+ currency?: string;
1204
+ schedule?: string | null;
1205
+ timezone?: string;
1206
+ status?: CatalogImportSourceStatus;
1207
+ }
1208
+ export interface UpdateCatalogImportSourceInput {
1209
+ connectorId?: string;
1210
+ spreadsheetId?: string;
1211
+ sheetTab?: string | null;
1212
+ range?: string;
1213
+ columnMapping?: CatalogImportColumnMapping;
1214
+ config?: {
1215
+ shop?: string;
1216
+ };
1217
+ currency?: string | null;
1218
+ schedule?: string | null;
1219
+ timezone?: string;
1220
+ status?: CatalogImportSourceStatus;
1221
+ }
1222
+ export interface PreviewCatalogImportSourceInput {
1223
+ spreadsheetId: string;
1224
+ sheetTab?: string;
1225
+ /** Defaults to a small header+sample window of the first tab. */
1226
+ range?: string;
1227
+ }
1228
+ export interface CatalogImportSourcePreview {
1229
+ headers: string[];
1230
+ sampleRows: string[][];
1231
+ suggestedMapping: CatalogImportColumnMapping;
1232
+ confidence?: 'high' | 'medium' | 'low';
1233
+ notes?: string;
1234
+ }
868
1235
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge-io/sdk-server",
3
- "version": "4.14.0",
3
+ "version": "4.16.0",
4
4
  "description": "Server-side SDK for backend apps integrating with AgentForge platform. Auth via ChatToken, ak_live_ API key or App secret (sk_live_), with App installations across tenants.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",