@pylo/node 0.0.11 → 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.
package/dist/index.js CHANGED
@@ -48,6 +48,7 @@ async function graphqlRequest(endpoint, query, variables, options) {
48
48
  }
49
49
 
50
50
  // ../core/dist/index.js
51
+ var VARIANT_SUFFIX = "_variants";
51
52
  var PAGINATION_FIELDS = `pagination {
52
53
  total
53
54
  current_page
@@ -55,92 +56,59 @@ var PAGINATION_FIELDS = `pagination {
55
56
  last_page
56
57
  has_more_pages
57
58
  }`;
58
- function buildSelectionSet(select, entityMeta, schemaMetadata, variables, variableTypes, prefix) {
59
- var _a, _b;
59
+ function buildSelectionSet(select, variables, variableTypes, prefix) {
60
60
  const fields = [];
61
- const variantFieldNames = (_a = entityMeta.variantFieldNames) != null ? _a : [];
62
- if (!select) {
63
- fields.push(...entityMeta.scalarFieldNames);
64
- for (const vf of variantFieldNames) {
65
- fields.push(`${vf} { data { value variant } }`);
66
- }
67
- return fields.join("\n ");
68
- }
69
61
  for (const [key, value] of Object.entries(select)) {
70
- if (entityMeta.scalarFieldNames.includes(key)) {
71
- if (value === true) {
62
+ if (value === true) {
63
+ if (key.endsWith(VARIANT_SUFFIX)) {
64
+ fields.push(`${key} { data { value variant } }`);
65
+ } else {
72
66
  fields.push(key);
73
67
  }
74
68
  continue;
75
69
  }
76
- if (variantFieldNames.includes(key)) {
77
- if (value === true) {
78
- fields.push(`${key} { data { value variant } }`);
79
- }
80
- continue;
70
+ if (typeof value !== "object" || value === null) continue;
71
+ const relation = value;
72
+ const argParts = [];
73
+ if (relation.filter !== void 0) {
74
+ const varName = `${prefix}${key}_filter`;
75
+ variables[varName] = relation.filter;
76
+ variableTypes.set(varName, "FilterInput");
77
+ argParts.push(`filter: $${varName}`);
81
78
  }
82
- const relation = entityMeta.relations[key];
83
- if (!relation) {
84
- if (schemaMetadata.unknownFieldBehavior === "ignore") continue;
85
- const validFields = [...entityMeta.scalarFieldNames, ...variantFieldNames].join(", ");
86
- const validRelations = Object.keys(entityMeta.relations).join(", ");
87
- throw new Error(
88
- `Unknown field "${key}" on entity "${entityMeta.pascalName}". Valid fields: ${validFields}. Valid relations: ${validRelations}`
89
- );
79
+ const wantsPagination = relation.pagination !== void 0;
80
+ if (wantsPagination) {
81
+ const varName = `${prefix}${key}_pagination`;
82
+ variables[varName] = relation.pagination;
83
+ variableTypes.set(varName, "PaginationInput");
84
+ argParts.push(`pagination: $${varName}`);
90
85
  }
91
- const targetMeta = schemaMetadata.entities[relation.entity];
92
- if (!targetMeta) continue;
93
- const isHasMany = relation.type === "hasMany";
94
- if (value === true) {
95
- const targetFieldParts = [...targetMeta.scalarFieldNames];
96
- for (const vf of (_b = targetMeta.variantFieldNames) != null ? _b : []) {
97
- targetFieldParts.push(`${vf} { data { value variant } }`);
98
- }
99
- const targetFields = targetFieldParts.join(" ");
100
- if (isHasMany) {
101
- fields.push(`${key} { data { ${targetFields} } ${PAGINATION_FIELDS} }`);
102
- } else {
103
- fields.push(`${key} { data { ${targetFields} } }`);
104
- }
105
- } else if (typeof value === "object" && value !== null) {
106
- const argParts = [];
107
- if (value.filter !== void 0) {
108
- const varName = `${prefix}${key}_filter`;
109
- variables[varName] = value.filter;
110
- variableTypes.set(varName, "FilterInput");
111
- argParts.push(`filter: $${varName}`);
112
- }
113
- if (isHasMany && value.pagination !== void 0) {
114
- const varName = `${prefix}${key}_pagination`;
115
- variables[varName] = value.pagination;
116
- variableTypes.set(varName, "PaginationInput");
117
- argParts.push(`pagination: $${varName}`);
118
- }
119
- const args = argParts.length > 0 ? `(${argParts.join(", ")})` : "";
120
- const nestedSelection = buildSelectionSet(
121
- value.select,
122
- targetMeta,
123
- schemaMetadata,
124
- variables,
125
- variableTypes,
126
- `${prefix}${key}_`
127
- );
128
- if (isHasMany) {
129
- fields.push(
130
- `${key}${args} { data { ${nestedSelection} } ${PAGINATION_FIELDS} }`
131
- );
132
- } else {
133
- fields.push(`${key}${args} { data { ${nestedSelection} } }`);
134
- }
86
+ const args = argParts.length > 0 ? `(${argParts.join(", ")})` : "";
87
+ if (!relation.select) {
88
+ throw new Error(`Relation "${key}" requires an explicit { select: {...} }.`);
89
+ }
90
+ const nestedSelection = buildSelectionSet(
91
+ relation.select,
92
+ variables,
93
+ variableTypes,
94
+ `${prefix}${key}_`
95
+ );
96
+ if (wantsPagination) {
97
+ fields.push(`${key}${args} { data { ${nestedSelection} } ${PAGINATION_FIELDS} }`);
98
+ } else {
99
+ fields.push(`${key}${args} { data { ${nestedSelection} } }`);
135
100
  }
136
101
  }
137
102
  return fields.join("\n ");
138
103
  }
139
- function buildListQuery(entityKey, options, schemaMetadata) {
140
- const entityMeta = schemaMetadata.entities[entityKey];
141
- if (!entityMeta) {
142
- throw new Error(`Unknown entity: ${entityKey}`);
104
+ function requireSelect(entityKey, operation, select) {
105
+ if (!select || typeof select !== "object" || Object.keys(select).length === 0) {
106
+ throw new Error(`${operation}("${entityKey}") requires an explicit 'select'.`);
143
107
  }
108
+ return select;
109
+ }
110
+ function buildListQuery(entityKey, options) {
111
+ const select = requireSelect(entityKey, "list", options == null ? void 0 : options.select);
144
112
  const variables = {};
145
113
  const variableTypes = /* @__PURE__ */ new Map();
146
114
  if ((options == null ? void 0 : options.filter) !== void 0) {
@@ -151,14 +119,7 @@ function buildListQuery(entityKey, options, schemaMetadata) {
151
119
  variables["pagination"] = options.pagination;
152
120
  variableTypes.set("pagination", "PaginationInput");
153
121
  }
154
- const selectionSet = buildSelectionSet(
155
- options == null ? void 0 : options.select,
156
- entityMeta,
157
- schemaMetadata,
158
- variables,
159
- variableTypes,
160
- "r_"
161
- );
122
+ const selectionSet = buildSelectionSet(select, variables, variableTypes, "r_");
162
123
  const varDecls = Array.from(variableTypes.entries()).map(([name, type]) => `$${name}: ${type}`).join(", ");
163
124
  const varSection = varDecls ? `(${varDecls})` : "";
164
125
  const argParts = [];
@@ -180,21 +141,11 @@ function buildListQuery(entityKey, options, schemaMetadata) {
180
141
  }`;
181
142
  return { query, variables };
182
143
  }
183
- function buildByIdQuery(entityKey, id, options, schemaMetadata) {
184
- const entityMeta = schemaMetadata.entities[entityKey];
185
- if (!entityMeta) {
186
- throw new Error(`Unknown entity: ${entityKey}`);
187
- }
144
+ function buildByIdQuery(entityKey, id, options) {
145
+ const select = requireSelect(entityKey, "byId", options == null ? void 0 : options.select);
188
146
  const variables = { id };
189
147
  const variableTypes = /* @__PURE__ */ new Map([["id", "ID!"]]);
190
- const selectionSet = buildSelectionSet(
191
- options == null ? void 0 : options.select,
192
- entityMeta,
193
- schemaMetadata,
194
- variables,
195
- variableTypes,
196
- "r_"
197
- );
148
+ const selectionSet = buildSelectionSet(select, variables, variableTypes, "r_");
198
149
  const varDecls = Array.from(variableTypes.entries()).map(([name, type]) => `$${name}: ${type}`).join(", ");
199
150
  const query = `query ${capitalize(entityKey)}ById(${varDecls}) {
200
151
  ${entityKey}ById(id: $id) {
@@ -208,6 +159,89 @@ function buildByIdQuery(entityKey, id, options, schemaMetadata) {
208
159
  function capitalize(str) {
209
160
  return str.charAt(0).toUpperCase() + str.slice(1);
210
161
  }
162
+ var EVENT_LIST_ARG_TYPES = {
163
+ filter: "EventListFilterInput",
164
+ pagination: "PaginationInput",
165
+ select_fields: "[String!]",
166
+ interval: "String",
167
+ timezone: "String",
168
+ group_by: "[String!]",
169
+ startTime: "String"
170
+ };
171
+ var EVENT_LIST_DATA = `data
172
+ pagination {
173
+ total
174
+ current_page
175
+ per_page
176
+ last_page
177
+ has_more_pages
178
+ }
179
+ aggregations`;
180
+ function normalizeEventFilter(filter) {
181
+ var _a;
182
+ if (!((_a = filter.dimensions) == null ? void 0 : _a.length)) return filter;
183
+ const dimensions = filter.dimensions.map(
184
+ (dim) => dim.timeBucket && dim.timeBucket.field === void 0 ? { ...dim, timeBucket: { ...dim.timeBucket, field: "ts" } } : dim
185
+ );
186
+ return { ...filter, dimensions };
187
+ }
188
+ function buildEventListQuery(options) {
189
+ const variables = {};
190
+ const varDecls = [];
191
+ const argParts = [];
192
+ for (const key of Object.keys(EVENT_LIST_ARG_TYPES)) {
193
+ const value = options == null ? void 0 : options[key];
194
+ if (value === void 0) continue;
195
+ variables[key] = key === "filter" ? normalizeEventFilter(value) : value;
196
+ varDecls.push(`$${key}: ${EVENT_LIST_ARG_TYPES[key]}`);
197
+ argParts.push(`${key}: $${key}`);
198
+ }
199
+ const varSection = varDecls.length > 0 ? `(${varDecls.join(", ")})` : "";
200
+ const argSection = argParts.length > 0 ? `(${argParts.join(", ")})` : "";
201
+ const query = `query PyloEventList${varSection} {
202
+ pyloEventList${argSection} {
203
+ ${EVENT_LIST_DATA}
204
+ }
205
+ }`;
206
+ return { query, variables };
207
+ }
208
+ function buildEventPropertyKeysQuery(options) {
209
+ const hasFilter = (options == null ? void 0 : options.filter) !== void 0;
210
+ const varSection = hasFilter ? "($filter: FilterInput)" : "";
211
+ const argSection = hasFilter ? "(filter: $filter)" : "";
212
+ const query = `query PyloEventPropertyKeys${varSection} {
213
+ pyloEventPropertyKeys${argSection} {
214
+ path
215
+ type
216
+ }
217
+ }`;
218
+ return {
219
+ query,
220
+ variables: hasFilter ? { filter: options.filter } : {}
221
+ };
222
+ }
223
+ function buildEventFieldValuesQuery(field, options) {
224
+ const varDecls = ["$field: String!"];
225
+ const argParts = ["field: $field"];
226
+ const variables = { field };
227
+ if ((options == null ? void 0 : options.startTime) !== void 0) {
228
+ varDecls.push("$startTime: String");
229
+ argParts.push("startTime: $startTime");
230
+ variables["startTime"] = options.startTime;
231
+ }
232
+ if ((options == null ? void 0 : options.limit) !== void 0) {
233
+ varDecls.push("$limit: Int");
234
+ argParts.push("limit: $limit");
235
+ variables["limit"] = options.limit;
236
+ }
237
+ const query = `query PyloEventFieldValues(${varDecls.join(", ")}) {
238
+ pyloEventFieldValues(${argParts.join(", ")}) {
239
+ value
240
+ count
241
+ }
242
+ }`;
243
+ return { query, variables };
244
+ }
211
245
  function buildUpsertMutation(_entityKey, pascalName, input) {
212
246
  const mutation = `mutation Update${pascalName}($input: Update${pascalName}Input!) {
213
247
  update${pascalName}(input: $input) {
@@ -286,13 +320,12 @@ async function executeGraphQL(endpoint, query, variables, auth, headers) {
286
320
  }
287
321
  return response.data;
288
322
  }
289
- function createEntityClient(entityKey, endpoint, metadata, auth, globalHeaders) {
323
+ function createEntityClient(entityKey, endpoint, auth, globalHeaders) {
290
324
  return {
291
325
  async list(options) {
292
326
  const { query, variables } = buildListQuery(
293
327
  entityKey,
294
- options,
295
- metadata
328
+ options
296
329
  );
297
330
  const data = await executeGraphQL(
298
331
  endpoint,
@@ -312,8 +345,7 @@ function createEntityClient(entityKey, endpoint, metadata, auth, globalHeaders)
312
345
  const { query, variables } = buildByIdQuery(
313
346
  entityKey,
314
347
  id,
315
- options,
316
- metadata
348
+ options
317
349
  );
318
350
  const data = await executeGraphQL(
319
351
  endpoint,
@@ -328,13 +360,10 @@ function createEntityClient(entityKey, endpoint, metadata, auth, globalHeaders)
328
360
  return result.data;
329
361
  },
330
362
  async upsert(input, options) {
331
- const entityMeta = metadata.entities[entityKey];
332
- if (!entityMeta) {
333
- throw new PyloError(`Unknown entity: ${entityKey}`);
334
- }
363
+ const pascalName = capitalize(entityKey);
335
364
  const { query, variables } = buildUpsertMutation(
336
365
  entityKey,
337
- entityMeta.pascalName,
366
+ pascalName,
338
367
  input
339
368
  );
340
369
  const data = await executeGraphQL(
@@ -347,7 +376,7 @@ function createEntityClient(entityKey, endpoint, metadata, auth, globalHeaders)
347
376
  flagsToHeaders(options != null ? options : {})
348
377
  )
349
378
  );
350
- const mutationKey = `update${entityMeta.pascalName}`;
379
+ const mutationKey = `update${pascalName}`;
351
380
  const result = data[mutationKey];
352
381
  if (!result) {
353
382
  throw new PyloError(`Unexpected response shape \u2014 missing ${mutationKey}`);
@@ -355,13 +384,10 @@ function createEntityClient(entityKey, endpoint, metadata, auth, globalHeaders)
355
384
  return result.data;
356
385
  },
357
386
  async delete(ids, options) {
358
- const entityMeta = metadata.entities[entityKey];
359
- if (!entityMeta) {
360
- throw new PyloError(`Unknown entity: ${entityKey}`);
361
- }
387
+ const pascalName = capitalize(entityKey);
362
388
  const { query, variables } = buildDeleteMutation(
363
389
  entityKey,
364
- entityMeta.pascalName,
390
+ pascalName,
365
391
  ids
366
392
  );
367
393
  const data = await executeGraphQL(
@@ -374,7 +400,7 @@ function createEntityClient(entityKey, endpoint, metadata, auth, globalHeaders)
374
400
  flagsToHeaders(options != null ? options : {})
375
401
  )
376
402
  );
377
- const mutationKey = `delete${entityMeta.pascalName}`;
403
+ const mutationKey = `delete${pascalName}`;
378
404
  const result = data[mutationKey];
379
405
  if (!result) {
380
406
  throw new PyloError(`Unexpected response shape \u2014 missing ${mutationKey}`);
@@ -403,17 +429,61 @@ function createIngestEvents(endpoint, auth, globalHeaders) {
403
429
  return result.data;
404
430
  };
405
431
  }
432
+ function createEventsClient(endpoint, auth, globalHeaders) {
433
+ return {
434
+ async list(options) {
435
+ const { query, variables } = buildEventListQuery(options);
436
+ const data = await executeGraphQL(
437
+ endpoint,
438
+ query,
439
+ variables,
440
+ auth,
441
+ mergeHeaders(globalHeaders, options == null ? void 0 : options.headers)
442
+ );
443
+ const result = data["pyloEventList"];
444
+ if (!result) {
445
+ throw new PyloError("Unexpected response shape \u2014 missing pyloEventList");
446
+ }
447
+ return result;
448
+ },
449
+ async propertyKeys(options) {
450
+ var _a;
451
+ const { query, variables } = buildEventPropertyKeysQuery(options);
452
+ const data = await executeGraphQL(
453
+ endpoint,
454
+ query,
455
+ variables,
456
+ auth,
457
+ mergeHeaders(globalHeaders, options == null ? void 0 : options.headers)
458
+ );
459
+ return (_a = data["pyloEventPropertyKeys"]) != null ? _a : [];
460
+ },
461
+ async fieldValues(field, options) {
462
+ var _a;
463
+ const { query, variables } = buildEventFieldValuesQuery(field, options);
464
+ const data = await executeGraphQL(
465
+ endpoint,
466
+ query,
467
+ variables,
468
+ auth,
469
+ mergeHeaders(globalHeaders, options == null ? void 0 : options.headers)
470
+ );
471
+ return (_a = data["pyloEventFieldValues"]) != null ? _a : [];
472
+ }
473
+ };
474
+ }
406
475
  function createPyloClient(options) {
407
476
  const endpoint = getEndpoint(options.endpoint);
408
- const metadata = options.schemaMetadata;
409
477
  const auth = options.auth;
410
478
  const globalHeaders = options.headers;
411
479
  const ingestEvents = createIngestEvents(endpoint, auth, globalHeaders);
480
+ const events = createEventsClient(endpoint, auth, globalHeaders);
412
481
  return new Proxy({}, {
413
482
  get(_target, prop) {
414
483
  if (typeof prop !== "string") return void 0;
415
484
  if (prop === "ingestEvents") return ingestEvents;
416
- return createEntityClient(prop, endpoint, metadata, auth, globalHeaders);
485
+ if (prop === "events") return events;
486
+ return createEntityClient(prop, endpoint, auth, globalHeaders);
417
487
  }
418
488
  });
419
489
  }
@@ -422,12 +492,26 @@ function createPyloClient(options) {
422
492
  function createPyloNode(options) {
423
493
  return createPyloClient({
424
494
  ...options.endpoint !== void 0 ? { endpoint: options.endpoint } : {},
425
- schemaMetadata: options.schemaMetadata,
426
495
  auth: async () => ({ apiKey: options.apiKey }),
427
496
  ...options.headers !== void 0 ? { headers: options.headers } : {}
428
497
  });
429
498
  }
499
+ var pylo = new Proxy(
500
+ {},
501
+ {
502
+ get(_target, prop) {
503
+ const client = globalThis["__PYLO_FLOW_CLIENT__"];
504
+ if (!client) {
505
+ throw new Error(
506
+ "Pylo flow client unavailable (globalThis.__PYLO_FLOW_CLIENT__ is unset). `pylo` is only usable inside a Pylo flow action."
507
+ );
508
+ }
509
+ return client[prop];
510
+ }
511
+ }
512
+ );
430
513
  export {
431
514
  PyloError,
432
- createPyloNode
515
+ createPyloNode,
516
+ pylo
433
517
  };
@@ -0,0 +1 @@
1
+ export { AnalyzedEntity, AnalyzedField, AnalyzedRelation, ENTITY_LIST_QUERY, EntityListResponse, RawEntity, RawEntityField, RawEntityRelation, SchemaFetcher, analyzeEntities, fetchSchemaWith, generateEntitiesFile, generateIndexFile } from '@pylo/core/schema';