@zeyos/client 0.1.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 (110) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +458 -0
  4. package/agents/README.md +66 -0
  5. package/agents/shared/business-app-benchmarks.md +111 -0
  6. package/agents/shared/zeyos-entity-map.md +142 -0
  7. package/agents/shared/zeyos-entity-reference.md +570 -0
  8. package/agents/shared/zeyos-query-patterns.md +89 -0
  9. package/agents/zeyos-account-intelligence/SKILL.md +34 -0
  10. package/agents/zeyos-account-intelligence/agents/openai.yaml +4 -0
  11. package/agents/zeyos-account-intelligence/references/workflows.md +84 -0
  12. package/agents/zeyos-billing-insights/SKILL.md +41 -0
  13. package/agents/zeyos-billing-insights/agents/openai.yaml +4 -0
  14. package/agents/zeyos-billing-insights/references/workflows.md +106 -0
  15. package/agents/zeyos-campaign-and-outreach/SKILL.md +44 -0
  16. package/agents/zeyos-campaign-and-outreach/agents/openai.yaml +4 -0
  17. package/agents/zeyos-campaign-and-outreach/references/workflows.md +100 -0
  18. package/agents/zeyos-collaboration-and-activity/SKILL.md +37 -0
  19. package/agents/zeyos-collaboration-and-activity/agents/openai.yaml +4 -0
  20. package/agents/zeyos-collaboration-and-activity/references/workflows.md +104 -0
  21. package/agents/zeyos-collections-and-dunning/SKILL.md +46 -0
  22. package/agents/zeyos-collections-and-dunning/agents/openai.yaml +4 -0
  23. package/agents/zeyos-collections-and-dunning/references/workflows.md +132 -0
  24. package/agents/zeyos-commerce-and-inventory/SKILL.md +38 -0
  25. package/agents/zeyos-commerce-and-inventory/agents/openai.yaml +4 -0
  26. package/agents/zeyos-commerce-and-inventory/references/workflows.md +101 -0
  27. package/agents/zeyos-mail-operations/SKILL.md +35 -0
  28. package/agents/zeyos-mail-operations/agents/openai.yaml +4 -0
  29. package/agents/zeyos-mail-operations/references/workflows.md +110 -0
  30. package/agents/zeyos-notes-and-sops/SKILL.md +31 -0
  31. package/agents/zeyos-notes-and-sops/agents/openai.yaml +4 -0
  32. package/agents/zeyos-notes-and-sops/references/workflows.md +85 -0
  33. package/agents/zeyos-platform-and-schema/SKILL.md +37 -0
  34. package/agents/zeyos-platform-and-schema/agents/openai.yaml +4 -0
  35. package/agents/zeyos-platform-and-schema/references/workflows.md +97 -0
  36. package/agents/zeyos-work-management/SKILL.md +45 -0
  37. package/agents/zeyos-work-management/agents/openai.yaml +4 -0
  38. package/agents/zeyos-work-management/references/workflows.md +148 -0
  39. package/docs/01-api-reference/01-data-retrieval.md +601 -0
  40. package/docs/01-api-reference/02-authentication.md +288 -0
  41. package/docs/01-api-reference/03-resources.md +270 -0
  42. package/docs/01-api-reference/04-schema.md +539 -0
  43. package/docs/01-api-reference/_category_.json +9 -0
  44. package/docs/02-javascript-client/01-getting-started.md +146 -0
  45. package/docs/02-javascript-client/02-authentication.md +287 -0
  46. package/docs/02-javascript-client/03-making-requests.md +572 -0
  47. package/docs/02-javascript-client/04-practical-guide.md +348 -0
  48. package/docs/02-javascript-client/_category_.json +9 -0
  49. package/docs/03-cli/01-getting-started.md +219 -0
  50. package/docs/03-cli/02-commands.md +407 -0
  51. package/docs/03-cli/03-configuration.md +220 -0
  52. package/docs/03-cli/_category_.json +9 -0
  53. package/docs/04-agent-workflows/00-coding-agents.md +35 -0
  54. package/docs/04-agent-workflows/01-agent-quickstart.md +147 -0
  55. package/docs/04-agent-workflows/02-agent-recipes.md +109 -0
  56. package/docs/04-agent-workflows/03-cli-coverage-and-escalation.md +65 -0
  57. package/docs/04-agent-workflows/_category_.json +9 -0
  58. package/docs/04-sample-apps/01-kanban.md +89 -0
  59. package/docs/04-sample-apps/02-crm.md +81 -0
  60. package/docs/04-sample-apps/03-dashboard.md +80 -0
  61. package/docs/04-sample-apps/_category_.json +9 -0
  62. package/docs/05-tutorials/00-application-developers.md +43 -0
  63. package/docs/05-tutorials/01-integration-architecture.md +60 -0
  64. package/docs/05-tutorials/02-build-your-own-zeyos-frontend.md +517 -0
  65. package/docs/05-tutorials/03-server-side-integrations.md +185 -0
  66. package/docs/05-tutorials/_category_.json +9 -0
  67. package/docs/intro.md +197 -0
  68. package/openapi/api.json +24308 -0
  69. package/openapi/auth.json +415 -0
  70. package/openapi/dbref.json +56223 -0
  71. package/openapi/oauth2.json +781 -0
  72. package/openapi/sdk.json +949 -0
  73. package/openapi/views.txt +642 -0
  74. package/package.json +49 -0
  75. package/samples/crm/README.md +28 -0
  76. package/samples/crm/index.html +327 -0
  77. package/samples/crm/js/api.js +208 -0
  78. package/samples/crm/js/auth.js +61 -0
  79. package/samples/crm/js/main.js +545 -0
  80. package/samples/crm/js/state.js +90 -0
  81. package/samples/crm/js/ui.js +51 -0
  82. package/samples/dashboard/README.md +28 -0
  83. package/samples/dashboard/index.html +280 -0
  84. package/samples/dashboard/js/api.js +197 -0
  85. package/samples/dashboard/js/auth.js +59 -0
  86. package/samples/dashboard/js/main.js +382 -0
  87. package/samples/dashboard/js/state.js +81 -0
  88. package/samples/dashboard/js/ui.js +48 -0
  89. package/samples/kanban/README.md +28 -0
  90. package/samples/kanban/index.html +263 -0
  91. package/samples/kanban/js/api.js +152 -0
  92. package/samples/kanban/js/auth.js +59 -0
  93. package/samples/kanban/js/constants.js +40 -0
  94. package/samples/kanban/js/kanban.js +246 -0
  95. package/samples/kanban/js/main.js +362 -0
  96. package/samples/kanban/js/modals.js +474 -0
  97. package/samples/kanban/js/settings.js +82 -0
  98. package/samples/kanban/js/state.js +118 -0
  99. package/samples/kanban/js/ui.js +49 -0
  100. package/scripts/generate-client.mjs +344 -0
  101. package/src/generated/operations.js +9772 -0
  102. package/src/generated/schema.js +8982 -0
  103. package/src/index.js +85 -0
  104. package/src/runtime/client.js +1208 -0
  105. package/src/runtime/error.js +29 -0
  106. package/src/runtime/http.js +174 -0
  107. package/src/runtime/request-shape.js +35 -0
  108. package/src/runtime/schema.js +206 -0
  109. package/src/runtime/suggest.js +74 -0
  110. package/src/runtime/token-store.js +105 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Shared UI utilities: toast notifications + loading overlay.
3
+ * Extracted into its own module to avoid circular imports between main.js and modals.js.
4
+ */
5
+
6
+ // ── Toast Notifications ─────────────────────────────────────────────────────
7
+
8
+ /**
9
+ * @param {string} message
10
+ * @param {'success'|'error'|'info'} type
11
+ */
12
+ export function showToast(message, type = 'info') {
13
+ const container = document.getElementById('toast-container');
14
+ if (!container) return;
15
+
16
+ const colors = {
17
+ success: 'bg-emerald-600',
18
+ error: 'bg-red-600',
19
+ info: 'bg-slate-700',
20
+ };
21
+
22
+ const toast = document.createElement('div');
23
+ toast.className =
24
+ `pointer-events-auto flex items-center gap-3 px-4 py-3 rounded-xl text-white text-sm shadow-xl ` +
25
+ `${colors[type] ?? colors.info} translate-y-2 opacity-0 transition-all duration-200`;
26
+ toast.textContent = message;
27
+
28
+ container.appendChild(toast);
29
+ // Trigger transition on next frame
30
+ requestAnimationFrame(() => {
31
+ requestAnimationFrame(() => toast.classList.remove('translate-y-2', 'opacity-0'));
32
+ });
33
+
34
+ const duration = type === 'error' ? 5000 : 3000;
35
+ setTimeout(() => {
36
+ toast.classList.add('opacity-0', 'translate-y-2');
37
+ toast.addEventListener('transitionend', () => toast.remove(), { once: true });
38
+ }, duration);
39
+ }
40
+
41
+ // ── Loading Overlay ─────────────────────────────────────────────────────────
42
+
43
+ export function showLoading() {
44
+ document.getElementById('loading-overlay')?.classList.remove('hidden');
45
+ }
46
+
47
+ export function hideLoading() {
48
+ document.getElementById('loading-overlay')?.classList.add('hidden');
49
+ }
@@ -0,0 +1,344 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const HTTP_METHODS = new Set(['get', 'put', 'post', 'delete', 'patch', 'head', 'options', 'trace']);
6
+
7
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
8
+ const SOURCES = [
9
+ { service: 'api', file: 'openapi/api.json' },
10
+ { service: 'oauth2', file: 'openapi/oauth2.json' },
11
+ { service: 'legacyAuth', file: 'openapi/auth.json' }
12
+ ];
13
+
14
+ function unescapePointerToken(token) {
15
+ return token.replace(/~1/g, '/').replace(/~0/g, '~');
16
+ }
17
+
18
+ function pointerGet(doc, ref) {
19
+ if (!ref.startsWith('#/')) {
20
+ throw new Error(`External $ref is not supported: ${ref}`);
21
+ }
22
+
23
+ const parts = ref.slice(2).split('/').map(unescapePointerToken);
24
+ let current = doc;
25
+ for (const part of parts) {
26
+ if (current == null || !Object.prototype.hasOwnProperty.call(current, part)) {
27
+ throw new Error(`Unresolvable $ref: ${ref}`);
28
+ }
29
+ current = current[part];
30
+ }
31
+ return current;
32
+ }
33
+
34
+ function resolveRef(doc, value) {
35
+ if (!value || typeof value !== 'object') {
36
+ return value;
37
+ }
38
+ if (typeof value.$ref === 'string') {
39
+ return pointerGet(doc, value.$ref);
40
+ }
41
+ return value;
42
+ }
43
+
44
+ function normalizeServer(server) {
45
+ const urlTemplate = server?.url || '';
46
+ const defaultVariables = {};
47
+
48
+ if (server?.variables && typeof server.variables === 'object') {
49
+ for (const [name, variable] of Object.entries(server.variables)) {
50
+ if (variable && typeof variable.default === 'string') {
51
+ defaultVariables[name] = variable.default;
52
+ }
53
+ }
54
+ }
55
+
56
+ const basePathTemplate = (() => {
57
+ const match = urlTemplate.match(/^https?:\/\/[^/]+(\/.*)$/i);
58
+ return match ? match[1] : '';
59
+ })();
60
+
61
+ return {
62
+ urlTemplate,
63
+ basePathTemplate,
64
+ defaultVariables
65
+ };
66
+ }
67
+
68
+ function normalizeParameters(doc, pathItem, operation) {
69
+ const combined = [
70
+ ...(Array.isArray(pathItem?.parameters) ? pathItem.parameters : []),
71
+ ...(Array.isArray(operation?.parameters) ? operation.parameters : [])
72
+ ];
73
+
74
+ const indexed = new Map();
75
+ for (const rawParameter of combined) {
76
+ const parameter = resolveRef(doc, rawParameter);
77
+ if (!parameter || typeof parameter !== 'object') {
78
+ continue;
79
+ }
80
+
81
+ const key = `${parameter.in || 'unknown'}:${parameter.name || 'unknown'}`;
82
+ indexed.set(key, {
83
+ name: parameter.name,
84
+ in: parameter.in,
85
+ required: Boolean(parameter.required)
86
+ });
87
+ }
88
+
89
+ const normalized = Array.from(indexed.values()).filter((parameter) => parameter.name && parameter.in);
90
+
91
+ return {
92
+ all: normalized,
93
+ path: normalized.filter((parameter) => parameter.in === 'path').map((parameter) => parameter.name),
94
+ query: normalized.filter((parameter) => parameter.in === 'query').map((parameter) => parameter.name),
95
+ header: normalized.filter((parameter) => parameter.in === 'header').map((parameter) => parameter.name)
96
+ };
97
+ }
98
+
99
+ function normalizeRequestBody(doc, operation) {
100
+ const requestBody = resolveRef(doc, operation?.requestBody);
101
+ if (!requestBody || typeof requestBody !== 'object') {
102
+ return {
103
+ required: false,
104
+ contentTypes: []
105
+ };
106
+ }
107
+
108
+ const content = requestBody.content && typeof requestBody.content === 'object' ? requestBody.content : {};
109
+ const contentTypes = Object.keys(content);
110
+
111
+ return {
112
+ required: Boolean(requestBody.required),
113
+ contentTypes
114
+ };
115
+ }
116
+
117
+ function normalizeOperationSecurity(doc, operation) {
118
+ if (Array.isArray(operation?.security)) {
119
+ return operation.security;
120
+ }
121
+ if (Array.isArray(doc.security)) {
122
+ return doc.security;
123
+ }
124
+ return [];
125
+ }
126
+
127
+ function buildOperationId({ operationId, method, route, existingIds }) {
128
+ if (operationId && !existingIds.has(operationId)) {
129
+ return operationId;
130
+ }
131
+
132
+ const routeToken = route
133
+ .replace(/[^a-zA-Z0-9{}]/g, '_')
134
+ .replace(/[{}]/g, '')
135
+ .replace(/_+/g, '_')
136
+ .replace(/^_|_$/g, '');
137
+
138
+ let candidate = operationId || `${method.toLowerCase()}_${routeToken || 'operation'}`;
139
+ let suffix = 1;
140
+
141
+ while (existingIds.has(candidate)) {
142
+ suffix += 1;
143
+ candidate = `${operationId || `${method.toLowerCase()}_${routeToken || 'operation'}`}_${suffix}`;
144
+ }
145
+
146
+ return candidate;
147
+ }
148
+
149
+ function collectOperations(doc) {
150
+ const operations = [];
151
+ const existingIds = new Set();
152
+
153
+ for (const [route, pathItem] of Object.entries(doc.paths || {})) {
154
+ for (const [method, operation] of Object.entries(pathItem || {})) {
155
+ if (!HTTP_METHODS.has(method)) {
156
+ continue;
157
+ }
158
+
159
+ const normalizedMethod = method.toUpperCase();
160
+ const parameters = normalizeParameters(doc, pathItem, operation);
161
+ const requestBody = normalizeRequestBody(doc, operation);
162
+ const security = normalizeOperationSecurity(doc, operation);
163
+ const finalOperationId = buildOperationId({
164
+ operationId: operation.operationId,
165
+ method: normalizedMethod,
166
+ route,
167
+ existingIds
168
+ });
169
+
170
+ existingIds.add(finalOperationId);
171
+
172
+ operations.push({
173
+ operationId: finalOperationId,
174
+ summary: operation.summary || '',
175
+ deprecated: Boolean(operation.deprecated),
176
+ method: normalizedMethod,
177
+ path: route,
178
+ security,
179
+ requestBodyRequired: requestBody.required,
180
+ requestContentTypes: requestBody.contentTypes,
181
+ parameterNames: {
182
+ path: parameters.path,
183
+ query: parameters.query,
184
+ header: parameters.header
185
+ }
186
+ });
187
+ }
188
+ }
189
+
190
+ operations.sort((a, b) => {
191
+ if (a.path !== b.path) {
192
+ return a.path.localeCompare(b.path);
193
+ }
194
+ return a.method.localeCompare(b.method);
195
+ });
196
+
197
+ return operations;
198
+ }
199
+
200
+ async function readSpecFile(relativePath) {
201
+ const absolutePath = path.join(ROOT, relativePath);
202
+ const raw = await readFile(absolutePath, 'utf8');
203
+ return JSON.parse(raw);
204
+ }
205
+
206
+ async function readOptionalSpecFile(relativePath) {
207
+ try {
208
+ return await readSpecFile(relativePath);
209
+ } catch (error) {
210
+ if (error?.code === 'ENOENT') {
211
+ return null;
212
+ }
213
+ throw error;
214
+ }
215
+ }
216
+
217
+ function buildServices(specEntries) {
218
+ const services = {};
219
+
220
+ for (const specEntry of specEntries) {
221
+ const { service, file, doc } = specEntry;
222
+ const firstServer = Array.isArray(doc.servers) ? doc.servers[0] : undefined;
223
+
224
+ services[service] = {
225
+ key: service,
226
+ source: file,
227
+ title: doc.info?.title || '',
228
+ version: doc.info?.version || '',
229
+ server: normalizeServer(firstServer),
230
+ globalSecurity: Array.isArray(doc.security) ? doc.security : [],
231
+ operations: collectOperations(doc)
232
+ };
233
+ }
234
+
235
+ return services;
236
+ }
237
+
238
+ function renderModule(generated) {
239
+ const payload = JSON.stringify(generated, null, 2);
240
+
241
+ return [
242
+ '// This file is auto-generated by scripts/generate-client.mjs',
243
+ '// Do not edit manually.',
244
+ '',
245
+ `export const GENERATED = ${payload};`,
246
+ 'export const SERVICES = GENERATED.services;',
247
+ "export const SERVICE_KEYS = Object.freeze(Object.keys(SERVICES));",
248
+ ''
249
+ ].join('\n');
250
+ }
251
+
252
+ // Enum values are documented inline in dbref descriptions as `N`=LABEL pairs,
253
+ // e.g. "Status (`0`=NOTSTARTED, `1`=AWAITINGACCEPTANCE, ...)". Extract them so
254
+ // the client can validate enum inputs and suggest valid values.
255
+ function parseEnum(description) {
256
+ if (typeof description !== 'string') return null;
257
+ const out = {};
258
+ let count = 0;
259
+ const re = /`(-?\d+)`\s*=\s*([A-Za-z0-9_]+)/g;
260
+ let match;
261
+ while ((match = re.exec(description)) !== null) {
262
+ out[match[1]] = match[2];
263
+ count += 1;
264
+ }
265
+ return count >= 2 ? out : null;
266
+ }
267
+
268
+ // Compact field/enum/foreign-key map derived from openapi/dbref.json. Much
269
+ // smaller than the raw dbref (drops storage, collation, constraints, triggers,
270
+ // stats, etc.) so it ships cheaply and powers runtime introspection.
271
+ function buildSchema(dbref) {
272
+ const schema = {};
273
+ if (!Array.isArray(dbref)) return schema;
274
+
275
+ for (const entity of dbref) {
276
+ if (!entity || typeof entity !== 'object' || !entity.name || !Array.isArray(entity.fields)) {
277
+ continue;
278
+ }
279
+
280
+ const fields = {};
281
+ for (const field of entity.fields) {
282
+ if (!field || typeof field !== 'object' || !field.name) continue;
283
+ const def = { type: field.type || 'unknown' };
284
+ if (field.indexed) def.indexed = true;
285
+ if (Array.isArray(field.fkeys) && field.fkeys.length > 0 && field.fkeys[0].table) {
286
+ def.fk = field.fkeys[0].table;
287
+ }
288
+ const enumValues = parseEnum(field.description);
289
+ if (enumValues) def.enum = enumValues;
290
+ fields[field.name] = def;
291
+ }
292
+
293
+ schema[entity.name] = { type: entity.type || 'table', fields };
294
+ }
295
+
296
+ return schema;
297
+ }
298
+
299
+ function renderSchemaModule(schema) {
300
+ return [
301
+ '// This file is auto-generated by scripts/generate-client.mjs',
302
+ '// Do not edit manually. Source: openapi/dbref.json',
303
+ '',
304
+ `export const SCHEMA = ${JSON.stringify(schema, null, 2)};`,
305
+ 'export const SCHEMA_RESOURCES = Object.freeze(Object.keys(SCHEMA));',
306
+ ''
307
+ ].join('\n');
308
+ }
309
+
310
+ async function main() {
311
+ const specEntries = [];
312
+
313
+ for (const source of SOURCES) {
314
+ const doc = await readSpecFile(source.file);
315
+ specEntries.push({ ...source, doc });
316
+ }
317
+
318
+ const generated = {
319
+ // Deterministic by default (avoids per-build/test git churn). Publish
320
+ // pipelines can stamp a real timestamp by setting ZEYOS_GENERATED_AT.
321
+ generatedAt: process.env.ZEYOS_GENERATED_AT ?? null,
322
+ services: buildServices(specEntries)
323
+ };
324
+
325
+ const outputFile = path.join(ROOT, 'src/generated/operations.js');
326
+ await mkdir(path.dirname(outputFile), { recursive: true });
327
+ await writeFile(outputFile, renderModule(generated), 'utf8');
328
+
329
+ const dbref = await readOptionalSpecFile('openapi/dbref.json');
330
+ const schema = buildSchema(dbref);
331
+ await writeFile(path.join(ROOT, 'src/generated/schema.js'), renderSchemaModule(schema), 'utf8');
332
+
333
+ const operationCount = Object.values(generated.services)
334
+ .map((service) => service.operations.length)
335
+ .reduce((sum, value) => sum + value, 0);
336
+
337
+ process.stdout.write(`Generated operations for ${Object.keys(generated.services).length} services (${operationCount} operations).\n`);
338
+ process.stdout.write(`Generated schema for ${Object.keys(schema).length} resources.\n`);
339
+ }
340
+
341
+ main().catch((error) => {
342
+ console.error(error);
343
+ process.exit(1);
344
+ });