@ekanos/cli 0.12.0 → 0.13.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.
Files changed (47) hide show
  1. package/dist/apps-api.d.ts +3 -2
  2. package/dist/apps-api.js +1 -5
  3. package/dist/apps-api.js.map +1 -1
  4. package/dist/commands/agents-edit.js +1 -1
  5. package/dist/commands/agents-edit.js.map +1 -1
  6. package/dist/commands/apps.d.ts +13 -4
  7. package/dist/commands/apps.js +117 -39
  8. package/dist/commands/apps.js.map +1 -1
  9. package/dist/commands/knowledge.d.ts +37 -0
  10. package/dist/commands/knowledge.js +364 -0
  11. package/dist/commands/knowledge.js.map +1 -0
  12. package/dist/commands/sources.d.ts +4 -0
  13. package/dist/commands/sources.js +115 -1
  14. package/dist/commands/sources.js.map +1 -1
  15. package/dist/commands/team-agents-triggers.js +2 -1
  16. package/dist/commands/team-agents-triggers.js.map +1 -1
  17. package/dist/commands/teams-connect.d.ts +25 -0
  18. package/dist/commands/teams-connect.js +242 -0
  19. package/dist/commands/teams-connect.js.map +1 -0
  20. package/dist/commands/teams-onboard.d.ts +5 -2
  21. package/dist/commands/teams-onboard.js +12 -40
  22. package/dist/commands/teams-onboard.js.map +1 -1
  23. package/dist/commands/teams.d.ts +60 -5
  24. package/dist/commands/teams.js +141 -46
  25. package/dist/commands/teams.js.map +1 -1
  26. package/dist/index.js +62 -6
  27. package/dist/index.js.map +1 -1
  28. package/dist/knowledge-api.d.ts +129 -0
  29. package/dist/knowledge-api.js +138 -0
  30. package/dist/knowledge-api.js.map +1 -0
  31. package/dist/source-products-api.d.ts +59 -0
  32. package/dist/source-products-api.js +113 -0
  33. package/dist/source-products-api.js.map +1 -0
  34. package/dist/team-connect-api.d.ts +244 -0
  35. package/dist/team-connect-api.js +95 -0
  36. package/dist/team-connect-api.js.map +1 -0
  37. package/dist/teams-api.d.ts +1 -0
  38. package/dist/teams-api.js +1 -1
  39. package/dist/teams-api.js.map +1 -1
  40. package/package.json +2 -2
  41. package/templates/package.json.tmpl +4 -4
  42. package/templates/skills/build-agent/SKILL.md +14 -1
  43. package/templates/skills/build-agent/references/agent-json.md +22 -6
  44. package/templates/skills/build-agent/references/app-setup.md +2 -1
  45. package/templates/skills/build-agent/references/set-up-an-integration.md +19 -8
  46. package/templates/skills/build-agent/references/triggers.md +44 -15
  47. package/templates/skills/ekanos-platform/SKILL.md +32 -6
@@ -0,0 +1,59 @@
1
+ import { z } from 'zod';
2
+ export declare const SourceProductSchema: z.ZodObject<{
3
+ slug: z.ZodString;
4
+ name: z.ZodString;
5
+ kind: z.ZodEnum<{
6
+ experience: "experience";
7
+ integration: "integration";
8
+ }>;
9
+ enabled: z.ZodBoolean;
10
+ lever: z.ZodEnum<{
11
+ entitlement: "entitlement";
12
+ flag: "flag";
13
+ plan: "plan";
14
+ }>;
15
+ registered: z.ZodBoolean;
16
+ }, z.core.$strip>;
17
+ export type SourceProduct = z.infer<typeof SourceProductSchema>;
18
+ export type SourceProductsApiResult<T> = {
19
+ status: 'ok';
20
+ data: T;
21
+ } | {
22
+ status: 'unauthorized';
23
+ };
24
+ export declare function listSourceProducts(host: string, token: string, source: string): Promise<SourceProductsApiResult<{
25
+ source: {
26
+ id: string;
27
+ slug: string;
28
+ name: string | null;
29
+ };
30
+ products: {
31
+ slug: string;
32
+ name: string;
33
+ kind: "experience" | "integration";
34
+ enabled: boolean;
35
+ lever: "entitlement" | "flag" | "plan";
36
+ registered: boolean;
37
+ }[];
38
+ canEnable: boolean;
39
+ }>>;
40
+ export declare function setSourceProduct(host: string, token: string, input: {
41
+ source: string;
42
+ product: string;
43
+ enabled: boolean;
44
+ }): Promise<SourceProductsApiResult<{
45
+ source: {
46
+ id: string;
47
+ slug: string;
48
+ name: string | null;
49
+ };
50
+ product: {
51
+ slug: string;
52
+ name: string;
53
+ kind: "experience" | "integration";
54
+ enabled: boolean;
55
+ lever: "entitlement" | "flag" | "plan";
56
+ registered: boolean;
57
+ };
58
+ changed: boolean;
59
+ }>>;
@@ -0,0 +1,113 @@
1
+ import { z } from 'zod';
2
+ import { request } from './auth/ekanos-api.js';
3
+ import { authRequiredError, forbiddenError, invalidStateError, networkError, notFoundError, usageError, } from './errors.js';
4
+ /**
5
+ * The CLI's client for a Source's products (`ekanos sources products`).
6
+ *
7
+ * GET /api/partner/sources/products?source=<slug|id>
8
+ * → { source, products: [{ slug, name, kind, enabled, lever, registered }], canEnable }
9
+ * PUT /api/partner/sources/products/<product>?source=<slug|id> enable
10
+ * DELETE /api/partner/sources/products/<product>?source=<slug|id> disable
11
+ * → { source, product, changed }
12
+ *
13
+ * → 401 / 3xx refresh once and retry
14
+ * → 403 SUPER_ADMIN_REQUIRED enabling is a super-admin grant, which an
15
+ * `ekanos login` session never carries
16
+ * → 409 REFUSED a dependency or demo-only guard refused
17
+ *
18
+ * The shapes are read here rather than from `@ekanos/integration-schema`, so
19
+ * this CLI works against a host without a schema release.
20
+ */
21
+ const SourceRefSchema = z.object({
22
+ id: z.string(),
23
+ slug: z.string(),
24
+ name: z.string().nullable(),
25
+ });
26
+ export const SourceProductSchema = z.object({
27
+ slug: z.string(),
28
+ name: z.string(),
29
+ kind: z.enum(['experience', 'integration']),
30
+ enabled: z.boolean(),
31
+ lever: z.enum(['flag', 'plan', 'entitlement']),
32
+ registered: z.boolean(),
33
+ });
34
+ const ListSchema = z.object({
35
+ source: SourceRefSchema,
36
+ products: z.array(SourceProductSchema),
37
+ canEnable: z.boolean(),
38
+ });
39
+ const ChangeSchema = z.object({
40
+ source: SourceRefSchema,
41
+ product: SourceProductSchema,
42
+ changed: z.boolean(),
43
+ });
44
+ export function listSourceProducts(host, token, source) {
45
+ return call(host, token, ListSchema, {
46
+ method: 'GET',
47
+ path: `/api/partner/sources/products?${new URLSearchParams({ source })}`,
48
+ });
49
+ }
50
+ export function setSourceProduct(host, token, input) {
51
+ return call(host, token, ChangeSchema, {
52
+ method: input.enabled ? 'PUT' : 'DELETE',
53
+ path: `/api/partner/sources/products/${encodeURIComponent(input.product)}?${new URLSearchParams({ source: input.source })}`,
54
+ });
55
+ }
56
+ async function call(host, accessToken, schema, init) {
57
+ const response = await request(`${host}${init.path}`, {
58
+ method: init.method,
59
+ headers: {
60
+ accept: 'application/json',
61
+ authorization: `Bearer ${accessToken}`,
62
+ },
63
+ });
64
+ if (response.status === 401 ||
65
+ (response.status >= 300 && response.status < 400)) {
66
+ return { status: 'unauthorized' };
67
+ }
68
+ const body = await readOptionalJson(response);
69
+ const code = typeof body.code === 'string' ? body.code : null;
70
+ const message = typeof body.error === 'string' && body.error ? body.error : null;
71
+ if (response.status === 403 && code === 'MFA_REQUIRED') {
72
+ throw authRequiredError(message !== null && message !== void 0 ? message : `${host} requires multi-factor authentication.`, 'Complete MFA in the browser, then run "ekanos login" again.');
73
+ }
74
+ if (response.status === 403 && code === 'SUPER_ADMIN_REQUIRED') {
75
+ throw forbiddenError(message !== null && message !== void 0 ? message : 'Only a super-admin enables a product for a Source.', 'A super-admin does it in the browser: /admin/sources → the Source → Products (Experiences are switched on the same page).');
76
+ }
77
+ if (response.status === 403) {
78
+ throw forbiddenError(message !== null && message !== void 0 ? message : 'Not permitted on this Source.', 'Run "ekanos sources" to list the sources you hold a seat on.');
79
+ }
80
+ if (response.status === 404) {
81
+ throw notFoundError(message !== null && message !== void 0 ? message : 'Not found.', code === 'PRODUCT_NOT_FOUND'
82
+ ? '"ekanos sources products" lists the catalog.'
83
+ : 'Run "ekanos sources" to list the sources you hold a seat on.');
84
+ }
85
+ if (response.status === 409) {
86
+ throw invalidStateError(message !== null && message !== void 0 ? message : 'The host refused the change.', '"ekanos sources products" shows what this Source has.');
87
+ }
88
+ if (response.status === 400) {
89
+ throw usageError(message !== null && message !== void 0 ? message : 'The host refused the request.', 'See "ekanos sources --help".');
90
+ }
91
+ if (!response.ok) {
92
+ throw networkError(`${host}${init.path.split('?')[0]} responded ${response.status}.`, response.status >= 500
93
+ ? 'The Ekanos deployment returned a server error. Retry shortly.'
94
+ : 'Confirm the host runs a build that includes the source products routes.');
95
+ }
96
+ const parsed = schema.safeParse(body.data);
97
+ if (!parsed.success) {
98
+ throw networkError(`${host}/api/partner/sources/products answered in a shape this CLI does not read.`, 'Run "ekanos upgrade" — the CLI and the host disagree on the source products contract.');
99
+ }
100
+ return { status: 'ok', data: parsed.data };
101
+ }
102
+ async function readOptionalJson(response) {
103
+ try {
104
+ const parsed = await response.json();
105
+ return typeof parsed === 'object' && parsed !== null
106
+ ? parsed
107
+ : {};
108
+ }
109
+ catch (_a) {
110
+ return {};
111
+ }
112
+ }
113
+ //# sourceMappingURL=source-products-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-products-api.js","sourceRoot":"","sources":["../src/source-products-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IAC3C,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;IACpB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;CACxB,CAAC,CAAC;AAGH,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,MAAM,EAAE,eAAe;IACvB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC;IACtC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;CACvB,CAAC,CAAC;AACH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,MAAM,EAAE,eAAe;IACvB,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;CACrB,CAAC,CAAC;AAMH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,KAAa,EACb,MAAc;IAEd,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE;QACnC,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,iCAAiC,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;KACzE,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,KAAa,EACb,KAA4D;IAE5D,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;QACrC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ;QACxC,IAAI,EAAE,iCAAiC,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;KAC5H,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,IAAI,CACjB,IAAY,EACZ,WAAmB,EACnB,MAAoB,EACpB,IAAwD;IAExD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE;QACpD,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;KACF,CAAC,CAAC;IAEH,IACE,QAAQ,CAAC,MAAM,KAAK,GAAG;QACvB,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,EACjD,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IACpC,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,MAAM,OAAO,GACX,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;QACvD,MAAM,iBAAiB,CACrB,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,GAAG,IAAI,wCAAwC,EAC1D,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,IAAI,KAAK,sBAAsB,EAAE,CAAC;QAC/D,MAAM,cAAc,CAClB,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,oDAAoD,EAC/D,2HAA2H,CAC5H,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,cAAc,CAClB,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,+BAA+B,EAC1C,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,aAAa,CACjB,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,YAAY,EACvB,IAAI,KAAK,mBAAmB;YAC1B,CAAC,CAAC,8CAA8C;YAChD,CAAC,CAAC,8DAA8D,CACnE,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,iBAAiB,CACrB,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,8BAA8B,EACzC,uDAAuD,CACxD,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,UAAU,CACd,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,+BAA+B,EAC1C,8BAA8B,CAC/B,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,YAAY,CAChB,GAAG,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,QAAQ,CAAC,MAAM,GAAG,EACjE,QAAQ,CAAC,MAAM,IAAI,GAAG;YACpB,CAAC,CAAC,+DAA+D;YACjE,CAAC,CAAC,yEAAyE,CAC9E,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,YAAY,CAChB,GAAG,IAAI,2EAA2E,EAClF,uFAAuF,CACxF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;AAC7C,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,QAAkB;IAElB,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;YAClD,CAAC,CAAE,MAAkC;YACrC,CAAC,CAAC,EAAE,CAAC;IACT,CAAC;eAAO,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC","sourcesContent":["import { z } from 'zod';\n\nimport { request } from './auth/ekanos-api';\nimport {\n authRequiredError,\n forbiddenError,\n invalidStateError,\n networkError,\n notFoundError,\n usageError,\n} from './errors';\n\n/**\n * The CLI's client for a Source's products (`ekanos sources products`).\n *\n * GET /api/partner/sources/products?source=<slug|id>\n * → { source, products: [{ slug, name, kind, enabled, lever, registered }], canEnable }\n * PUT /api/partner/sources/products/<product>?source=<slug|id> enable\n * DELETE /api/partner/sources/products/<product>?source=<slug|id> disable\n * → { source, product, changed }\n *\n * → 401 / 3xx refresh once and retry\n * → 403 SUPER_ADMIN_REQUIRED enabling is a super-admin grant, which an\n * `ekanos login` session never carries\n * → 409 REFUSED a dependency or demo-only guard refused\n *\n * The shapes are read here rather than from `@ekanos/integration-schema`, so\n * this CLI works against a host without a schema release.\n */\n\nconst SourceRefSchema = z.object({\n id: z.string(),\n slug: z.string(),\n name: z.string().nullable(),\n});\n\nexport const SourceProductSchema = z.object({\n slug: z.string(),\n name: z.string(),\n kind: z.enum(['experience', 'integration']),\n enabled: z.boolean(),\n lever: z.enum(['flag', 'plan', 'entitlement']),\n registered: z.boolean(),\n});\nexport type SourceProduct = z.infer<typeof SourceProductSchema>;\n\nconst ListSchema = z.object({\n source: SourceRefSchema,\n products: z.array(SourceProductSchema),\n canEnable: z.boolean(),\n});\nconst ChangeSchema = z.object({\n source: SourceRefSchema,\n product: SourceProductSchema,\n changed: z.boolean(),\n});\n\nexport type SourceProductsApiResult<T> =\n | { status: 'ok'; data: T }\n | { status: 'unauthorized' };\n\nexport function listSourceProducts(\n host: string,\n token: string,\n source: string,\n) {\n return call(host, token, ListSchema, {\n method: 'GET',\n path: `/api/partner/sources/products?${new URLSearchParams({ source })}`,\n });\n}\n\nexport function setSourceProduct(\n host: string,\n token: string,\n input: { source: string; product: string; enabled: boolean },\n) {\n return call(host, token, ChangeSchema, {\n method: input.enabled ? 'PUT' : 'DELETE',\n path: `/api/partner/sources/products/${encodeURIComponent(input.product)}?${new URLSearchParams({ source: input.source })}`,\n });\n}\n\nasync function call<T>(\n host: string,\n accessToken: string,\n schema: z.ZodType<T>,\n init: { method: 'GET' | 'PUT' | 'DELETE'; path: string },\n): Promise<SourceProductsApiResult<T>> {\n const response = await request(`${host}${init.path}`, {\n method: init.method,\n headers: {\n accept: 'application/json',\n authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (\n response.status === 401 ||\n (response.status >= 300 && response.status < 400)\n ) {\n return { status: 'unauthorized' };\n }\n\n const body = await readOptionalJson(response);\n const code = typeof body.code === 'string' ? body.code : null;\n const message =\n typeof body.error === 'string' && body.error ? body.error : null;\n\n if (response.status === 403 && code === 'MFA_REQUIRED') {\n throw authRequiredError(\n message ?? `${host} requires multi-factor authentication.`,\n 'Complete MFA in the browser, then run \"ekanos login\" again.',\n );\n }\n if (response.status === 403 && code === 'SUPER_ADMIN_REQUIRED') {\n throw forbiddenError(\n message ?? 'Only a super-admin enables a product for a Source.',\n 'A super-admin does it in the browser: /admin/sources → the Source → Products (Experiences are switched on the same page).',\n );\n }\n if (response.status === 403) {\n throw forbiddenError(\n message ?? 'Not permitted on this Source.',\n 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 404) {\n throw notFoundError(\n message ?? 'Not found.',\n code === 'PRODUCT_NOT_FOUND'\n ? '\"ekanos sources products\" lists the catalog.'\n : 'Run \"ekanos sources\" to list the sources you hold a seat on.',\n );\n }\n if (response.status === 409) {\n throw invalidStateError(\n message ?? 'The host refused the change.',\n '\"ekanos sources products\" shows what this Source has.',\n );\n }\n if (response.status === 400) {\n throw usageError(\n message ?? 'The host refused the request.',\n 'See \"ekanos sources --help\".',\n );\n }\n if (!response.ok) {\n throw networkError(\n `${host}${init.path.split('?')[0]} responded ${response.status}.`,\n response.status >= 500\n ? 'The Ekanos deployment returned a server error. Retry shortly.'\n : 'Confirm the host runs a build that includes the source products routes.',\n );\n }\n\n const parsed = schema.safeParse(body.data);\n if (!parsed.success) {\n throw networkError(\n `${host}/api/partner/sources/products answered in a shape this CLI does not read.`,\n 'Run \"ekanos upgrade\" — the CLI and the host disagree on the source products contract.',\n );\n }\n return { status: 'ok', data: parsed.data };\n}\n\nasync function readOptionalJson(\n response: Response,\n): Promise<Record<string, unknown>> {\n try {\n const parsed: unknown = await response.json();\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n"]}
@@ -0,0 +1,244 @@
1
+ import { z } from 'zod';
2
+ import { type TeamsApiResult } from './teams-api.js';
3
+ /**
4
+ * The CLI's client for connecting a product for a team (`ekanos teams
5
+ * connect`), for the team's Source admin.
6
+ *
7
+ * GET /api/partner/teams/<team>/integrations/<product>/connect?source=<slug>[&as=<email>]
8
+ * → { plan }
9
+ * POST /api/partner/teams/<team>/integrations/<product>/connect?source=<slug>
10
+ * { as?, fields? }
11
+ * → { plan, result: "activated" } fields / no-fields
12
+ * → { plan, result: "consent", authorizeUrl, expiresAt } oauth
13
+ *
14
+ * The plan's `mode`, decided by the host, says how the product is
15
+ * connected. The shapes are read here rather than from
16
+ * `@ekanos/integration-schema`, so this CLI works against a host without a
17
+ * schema release.
18
+ */
19
+ export declare const TeamConnectPlanSchema: z.ZodObject<{
20
+ source: z.ZodObject<{
21
+ id: z.ZodString;
22
+ slug: z.ZodString;
23
+ name: z.ZodNullable<z.ZodString>;
24
+ }, z.core.$strip>;
25
+ team: z.ZodObject<{
26
+ slug: z.ZodString;
27
+ name: z.ZodString;
28
+ }, z.core.$strip>;
29
+ product: z.ZodObject<{
30
+ slug: z.ZodString;
31
+ name: z.ZodString;
32
+ kind: z.ZodNullable<z.ZodEnum<{
33
+ experience: "experience";
34
+ integration: "integration";
35
+ }>>;
36
+ }, z.core.$strip>;
37
+ scope: z.ZodEnum<{
38
+ team: "team";
39
+ user: "user";
40
+ }>;
41
+ mode: z.ZodEnum<{
42
+ browser: "browser";
43
+ fields: "fields";
44
+ "no-fields": "no-fields";
45
+ "not-entitled": "not-entitled";
46
+ "not-self-serve": "not-self-serve";
47
+ oauth: "oauth";
48
+ unsupported: "unsupported";
49
+ "works-as-shipped": "works-as-shipped";
50
+ }>;
51
+ reason: z.ZodNullable<z.ZodString>;
52
+ fields: z.ZodArray<z.ZodObject<{
53
+ name: z.ZodString;
54
+ label: z.ZodString;
55
+ description: z.ZodNullable<z.ZodString>;
56
+ sensitive: z.ZodBoolean;
57
+ required: z.ZodBoolean;
58
+ }, z.core.$strip>>;
59
+ teamApp: z.ZodBoolean;
60
+ member: z.ZodNullable<z.ZodObject<{
61
+ userId: z.ZodString;
62
+ email: z.ZodNullable<z.ZodString>;
63
+ isCaller: z.ZodBoolean;
64
+ }, z.core.$strip>>;
65
+ memberProblem: z.ZodNullable<z.ZodString>;
66
+ connected: z.ZodBoolean;
67
+ connectedAt: z.ZodNullable<z.ZodString>;
68
+ connectUrl: z.ZodString;
69
+ }, z.core.$strip>;
70
+ export type TeamConnectPlan = z.infer<typeof TeamConnectPlanSchema>;
71
+ declare const ShowSchema: z.ZodObject<{
72
+ plan: z.ZodObject<{
73
+ source: z.ZodObject<{
74
+ id: z.ZodString;
75
+ slug: z.ZodString;
76
+ name: z.ZodNullable<z.ZodString>;
77
+ }, z.core.$strip>;
78
+ team: z.ZodObject<{
79
+ slug: z.ZodString;
80
+ name: z.ZodString;
81
+ }, z.core.$strip>;
82
+ product: z.ZodObject<{
83
+ slug: z.ZodString;
84
+ name: z.ZodString;
85
+ kind: z.ZodNullable<z.ZodEnum<{
86
+ experience: "experience";
87
+ integration: "integration";
88
+ }>>;
89
+ }, z.core.$strip>;
90
+ scope: z.ZodEnum<{
91
+ team: "team";
92
+ user: "user";
93
+ }>;
94
+ mode: z.ZodEnum<{
95
+ browser: "browser";
96
+ fields: "fields";
97
+ "no-fields": "no-fields";
98
+ "not-entitled": "not-entitled";
99
+ "not-self-serve": "not-self-serve";
100
+ oauth: "oauth";
101
+ unsupported: "unsupported";
102
+ "works-as-shipped": "works-as-shipped";
103
+ }>;
104
+ reason: z.ZodNullable<z.ZodString>;
105
+ fields: z.ZodArray<z.ZodObject<{
106
+ name: z.ZodString;
107
+ label: z.ZodString;
108
+ description: z.ZodNullable<z.ZodString>;
109
+ sensitive: z.ZodBoolean;
110
+ required: z.ZodBoolean;
111
+ }, z.core.$strip>>;
112
+ teamApp: z.ZodBoolean;
113
+ member: z.ZodNullable<z.ZodObject<{
114
+ userId: z.ZodString;
115
+ email: z.ZodNullable<z.ZodString>;
116
+ isCaller: z.ZodBoolean;
117
+ }, z.core.$strip>>;
118
+ memberProblem: z.ZodNullable<z.ZodString>;
119
+ connected: z.ZodBoolean;
120
+ connectedAt: z.ZodNullable<z.ZodString>;
121
+ connectUrl: z.ZodString;
122
+ }, z.core.$strip>;
123
+ }, z.core.$strip>;
124
+ declare const StartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
125
+ plan: z.ZodObject<{
126
+ source: z.ZodObject<{
127
+ id: z.ZodString;
128
+ slug: z.ZodString;
129
+ name: z.ZodNullable<z.ZodString>;
130
+ }, z.core.$strip>;
131
+ team: z.ZodObject<{
132
+ slug: z.ZodString;
133
+ name: z.ZodString;
134
+ }, z.core.$strip>;
135
+ product: z.ZodObject<{
136
+ slug: z.ZodString;
137
+ name: z.ZodString;
138
+ kind: z.ZodNullable<z.ZodEnum<{
139
+ experience: "experience";
140
+ integration: "integration";
141
+ }>>;
142
+ }, z.core.$strip>;
143
+ scope: z.ZodEnum<{
144
+ team: "team";
145
+ user: "user";
146
+ }>;
147
+ mode: z.ZodEnum<{
148
+ browser: "browser";
149
+ fields: "fields";
150
+ "no-fields": "no-fields";
151
+ "not-entitled": "not-entitled";
152
+ "not-self-serve": "not-self-serve";
153
+ oauth: "oauth";
154
+ unsupported: "unsupported";
155
+ "works-as-shipped": "works-as-shipped";
156
+ }>;
157
+ reason: z.ZodNullable<z.ZodString>;
158
+ fields: z.ZodArray<z.ZodObject<{
159
+ name: z.ZodString;
160
+ label: z.ZodString;
161
+ description: z.ZodNullable<z.ZodString>;
162
+ sensitive: z.ZodBoolean;
163
+ required: z.ZodBoolean;
164
+ }, z.core.$strip>>;
165
+ teamApp: z.ZodBoolean;
166
+ member: z.ZodNullable<z.ZodObject<{
167
+ userId: z.ZodString;
168
+ email: z.ZodNullable<z.ZodString>;
169
+ isCaller: z.ZodBoolean;
170
+ }, z.core.$strip>>;
171
+ memberProblem: z.ZodNullable<z.ZodString>;
172
+ connected: z.ZodBoolean;
173
+ connectedAt: z.ZodNullable<z.ZodString>;
174
+ connectUrl: z.ZodString;
175
+ }, z.core.$strip>;
176
+ result: z.ZodLiteral<"activated">;
177
+ }, z.core.$strip>, z.ZodObject<{
178
+ plan: z.ZodObject<{
179
+ source: z.ZodObject<{
180
+ id: z.ZodString;
181
+ slug: z.ZodString;
182
+ name: z.ZodNullable<z.ZodString>;
183
+ }, z.core.$strip>;
184
+ team: z.ZodObject<{
185
+ slug: z.ZodString;
186
+ name: z.ZodString;
187
+ }, z.core.$strip>;
188
+ product: z.ZodObject<{
189
+ slug: z.ZodString;
190
+ name: z.ZodString;
191
+ kind: z.ZodNullable<z.ZodEnum<{
192
+ experience: "experience";
193
+ integration: "integration";
194
+ }>>;
195
+ }, z.core.$strip>;
196
+ scope: z.ZodEnum<{
197
+ team: "team";
198
+ user: "user";
199
+ }>;
200
+ mode: z.ZodEnum<{
201
+ browser: "browser";
202
+ fields: "fields";
203
+ "no-fields": "no-fields";
204
+ "not-entitled": "not-entitled";
205
+ "not-self-serve": "not-self-serve";
206
+ oauth: "oauth";
207
+ unsupported: "unsupported";
208
+ "works-as-shipped": "works-as-shipped";
209
+ }>;
210
+ reason: z.ZodNullable<z.ZodString>;
211
+ fields: z.ZodArray<z.ZodObject<{
212
+ name: z.ZodString;
213
+ label: z.ZodString;
214
+ description: z.ZodNullable<z.ZodString>;
215
+ sensitive: z.ZodBoolean;
216
+ required: z.ZodBoolean;
217
+ }, z.core.$strip>>;
218
+ teamApp: z.ZodBoolean;
219
+ member: z.ZodNullable<z.ZodObject<{
220
+ userId: z.ZodString;
221
+ email: z.ZodNullable<z.ZodString>;
222
+ isCaller: z.ZodBoolean;
223
+ }, z.core.$strip>>;
224
+ memberProblem: z.ZodNullable<z.ZodString>;
225
+ connected: z.ZodBoolean;
226
+ connectedAt: z.ZodNullable<z.ZodString>;
227
+ connectUrl: z.ZodString;
228
+ }, z.core.$strip>;
229
+ result: z.ZodLiteral<"consent">;
230
+ authorizeUrl: z.ZodString;
231
+ expiresAt: z.ZodString;
232
+ }, z.core.$strip>], "result">;
233
+ export type TeamConnectStart = z.infer<typeof StartSchema>;
234
+ interface Target {
235
+ source: string;
236
+ team: string;
237
+ product: string;
238
+ }
239
+ export declare function showTeamConnect(host: string, accessToken: string, target: Target, asEmail?: string): Promise<TeamsApiResult<z.infer<typeof ShowSchema>>>;
240
+ export declare function startTeamConnect(host: string, accessToken: string, target: Target, body: {
241
+ as?: string;
242
+ fields?: Record<string, string>;
243
+ }): Promise<TeamsApiResult<TeamConnectStart>>;
244
+ export {};
@@ -0,0 +1,95 @@
1
+ import { z } from 'zod';
2
+ import { call } from './teams-api.js';
3
+ /**
4
+ * The CLI's client for connecting a product for a team (`ekanos teams
5
+ * connect`), for the team's Source admin.
6
+ *
7
+ * GET /api/partner/teams/<team>/integrations/<product>/connect?source=<slug>[&as=<email>]
8
+ * → { plan }
9
+ * POST /api/partner/teams/<team>/integrations/<product>/connect?source=<slug>
10
+ * { as?, fields? }
11
+ * → { plan, result: "activated" } fields / no-fields
12
+ * → { plan, result: "consent", authorizeUrl, expiresAt } oauth
13
+ *
14
+ * The plan's `mode`, decided by the host, says how the product is
15
+ * connected. The shapes are read here rather than from
16
+ * `@ekanos/integration-schema`, so this CLI works against a host without a
17
+ * schema release.
18
+ */
19
+ export const TeamConnectPlanSchema = z.object({
20
+ source: z.object({
21
+ id: z.string(),
22
+ slug: z.string(),
23
+ name: z.string().nullable(),
24
+ }),
25
+ team: z.object({ slug: z.string(), name: z.string() }),
26
+ product: z.object({
27
+ slug: z.string(),
28
+ name: z.string(),
29
+ kind: z.enum(['experience', 'integration']).nullable(),
30
+ }),
31
+ scope: z.enum(['team', 'user']),
32
+ mode: z.enum([
33
+ 'unsupported',
34
+ 'not-entitled',
35
+ 'not-self-serve',
36
+ 'works-as-shipped',
37
+ 'oauth',
38
+ 'fields',
39
+ 'no-fields',
40
+ 'browser',
41
+ ]),
42
+ reason: z.string().nullable(),
43
+ fields: z.array(z.object({
44
+ name: z.string(),
45
+ label: z.string(),
46
+ description: z.string().nullable(),
47
+ sensitive: z.boolean(),
48
+ required: z.boolean(),
49
+ })),
50
+ teamApp: z.boolean(),
51
+ member: z
52
+ .object({
53
+ userId: z.string(),
54
+ email: z.string().nullable(),
55
+ isCaller: z.boolean(),
56
+ })
57
+ .nullable(),
58
+ memberProblem: z.string().nullable(),
59
+ connected: z.boolean(),
60
+ connectedAt: z.string().nullable(),
61
+ connectUrl: z.string(),
62
+ });
63
+ const ShowSchema = z.object({ plan: TeamConnectPlanSchema });
64
+ const StartSchema = z.discriminatedUnion('result', [
65
+ z.object({ plan: TeamConnectPlanSchema, result: z.literal('activated') }),
66
+ z.object({
67
+ plan: TeamConnectPlanSchema,
68
+ result: z.literal('consent'),
69
+ authorizeUrl: z.string(),
70
+ expiresAt: z.string(),
71
+ }),
72
+ ]);
73
+ function connectPath(target) {
74
+ return `/api/partner/teams/${encodeURIComponent(target.team)}/integrations/${encodeURIComponent(target.product)}/connect`;
75
+ }
76
+ export function showTeamConnect(host, accessToken, target, asEmail) {
77
+ // `call` puts `source` in the query; `as` rides in the path's own query.
78
+ const path = asEmail
79
+ ? `${connectPath(target)}?${new URLSearchParams({ as: asEmail })}`
80
+ : connectPath(target);
81
+ return call(host, accessToken, ShowSchema, {
82
+ method: 'GET',
83
+ path,
84
+ source: target.source,
85
+ });
86
+ }
87
+ export function startTeamConnect(host, accessToken, target, body) {
88
+ return call(host, accessToken, StartSchema, {
89
+ method: 'POST',
90
+ path: connectPath(target),
91
+ source: target.source,
92
+ body,
93
+ });
94
+ }
95
+ //# sourceMappingURL=team-connect-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-connect-api.js","sourceRoot":"","sources":["../src/team-connect-api.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\n\nimport { type TeamsApiResult, call } from './teams-api';\n\n/**\n * The CLI's client for connecting a product for a team (`ekanos teams\n * connect`), for the team's Source admin.\n *\n * GET /api/partner/teams/<team>/integrations/<product>/connect?source=<slug>[&as=<email>]\n * → { plan }\n * POST /api/partner/teams/<team>/integrations/<product>/connect?source=<slug>\n * { as?, fields? }\n * → { plan, result: \"activated\" } fields / no-fields\n * → { plan, result: \"consent\", authorizeUrl, expiresAt } oauth\n *\n * The plan's `mode`, decided by the host, says how the product is\n * connected. The shapes are read here rather than from\n * `@ekanos/integration-schema`, so this CLI works against a host without a\n * schema release.\n */\n\nexport const TeamConnectPlanSchema = z.object({\n source: z.object({\n id: z.string(),\n slug: z.string(),\n name: z.string().nullable(),\n }),\n team: z.object({ slug: z.string(), name: z.string() }),\n product: z.object({\n slug: z.string(),\n name: z.string(),\n kind: z.enum(['experience', 'integration']).nullable(),\n }),\n scope: z.enum(['team', 'user']),\n mode: z.enum([\n 'unsupported',\n 'not-entitled',\n 'not-self-serve',\n 'works-as-shipped',\n 'oauth',\n 'fields',\n 'no-fields',\n 'browser',\n ]),\n reason: z.string().nullable(),\n fields: z.array(\n z.object({\n name: z.string(),\n label: z.string(),\n description: z.string().nullable(),\n sensitive: z.boolean(),\n required: z.boolean(),\n }),\n ),\n teamApp: z.boolean(),\n member: z\n .object({\n userId: z.string(),\n email: z.string().nullable(),\n isCaller: z.boolean(),\n })\n .nullable(),\n memberProblem: z.string().nullable(),\n connected: z.boolean(),\n connectedAt: z.string().nullable(),\n connectUrl: z.string(),\n});\nexport type TeamConnectPlan = z.infer<typeof TeamConnectPlanSchema>;\n\nconst ShowSchema = z.object({ plan: TeamConnectPlanSchema });\nconst StartSchema = z.discriminatedUnion('result', [\n z.object({ plan: TeamConnectPlanSchema, result: z.literal('activated') }),\n z.object({\n plan: TeamConnectPlanSchema,\n result: z.literal('consent'),\n authorizeUrl: z.string(),\n expiresAt: z.string(),\n }),\n]);\nexport type TeamConnectStart = z.infer<typeof StartSchema>;\n\ninterface Target {\n source: string;\n team: string;\n product: string;\n}\n\nfunction connectPath(target: Target): string {\n return `/api/partner/teams/${encodeURIComponent(target.team)}/integrations/${encodeURIComponent(target.product)}/connect`;\n}\n\nexport function showTeamConnect(\n host: string,\n accessToken: string,\n target: Target,\n asEmail?: string,\n): Promise<TeamsApiResult<z.infer<typeof ShowSchema>>> {\n // `call` puts `source` in the query; `as` rides in the path's own query.\n const path = asEmail\n ? `${connectPath(target)}?${new URLSearchParams({ as: asEmail })}`\n : connectPath(target);\n return call(host, accessToken, ShowSchema, {\n method: 'GET',\n path,\n source: target.source,\n });\n}\n\nexport function startTeamConnect(\n host: string,\n accessToken: string,\n target: Target,\n body: { as?: string; fields?: Record<string, string> },\n): Promise<TeamsApiResult<TeamConnectStart>> {\n return call(host, accessToken, StartSchema, {\n method: 'POST',\n path: connectPath(target),\n source: target.source,\n body,\n });\n}\n"]}
@@ -44,6 +44,7 @@ export declare function setTeamApp(host: string, accessToken: string, target: {
44
44
  }, body: {
45
45
  connectionId?: string;
46
46
  fields: Record<string, string>;
47
+ clear?: string[];
47
48
  }): Promise<TeamsApiResult<TeamAppSetResult>>;
48
49
  export declare function mintTeamWebhook(host: string, accessToken: string, target: {
49
50
  source: string;
package/dist/teams-api.js CHANGED
@@ -83,7 +83,7 @@ function integrationPath(target) {
83
83
  }
84
84
  /** One partner teams call; shared by the team-agent clients (`team-agents-api.ts`). */
85
85
  export async function call(host, accessToken, schema, init) {
86
- const response = await request(`${host}${init.path}?${new URLSearchParams({ source: init.source })}`, {
86
+ const response = await request(`${host}${init.path}${init.path.includes('?') ? '&' : '?'}${new URLSearchParams({ source: init.source })}`, {
87
87
  method: init.method,
88
88
  headers: Object.assign({ accept: 'application/json', authorization: `Bearer ${accessToken}` }, (init.body === undefined
89
89
  ? {}