nextjs-hasura-auth 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/APOLLO.md +148 -0
- package/GENERATOR.md +671 -0
- package/README.md +154 -0
- package/dist/lib/apollo.d.ts +45 -0
- package/dist/lib/apollo.js +206 -0
- package/dist/lib/debug.d.ts +12 -0
- package/dist/lib/debug.js +24 -0
- package/dist/lib/generator.d.ts +33 -0
- package/dist/lib/generator.js +548 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.js +20 -0
- package/dist/lib/jwt.d.ts +67 -0
- package/dist/lib/jwt.js +195 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +8 -0
- package/dist/package.json +113 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +116 -0
@@ -0,0 +1,548 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
3
|
+
var t = {};
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
5
|
+
t[p] = s[p];
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
9
|
+
t[p[i]] = s[p[i]];
|
10
|
+
}
|
11
|
+
return t;
|
12
|
+
};
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
exports.Generator = Generator;
|
18
|
+
const debug_1 = __importDefault(require("./debug"));
|
19
|
+
// @ts-ignore // Assuming debug.js is moved to lib/debug.ts or similar and returns a function
|
20
|
+
const debug = (0, debug_1.default)('apollo:generator');
|
21
|
+
const core_1 = require("@apollo/client/core"); // Use core for gql
|
22
|
+
/**
|
23
|
+
* Creates a GraphQL query generator based on the provided schema.
|
24
|
+
*
|
25
|
+
* @param schema - The GraphQL schema in schema.json format.
|
26
|
+
* @returns A function to generate queries.
|
27
|
+
*/
|
28
|
+
function Generator(schema) {
|
29
|
+
// Check schema structure
|
30
|
+
if (!schema || !schema.first_level_queries) {
|
31
|
+
throw new Error('❌ Invalid schema format. Schema must contain first_level_queries field');
|
32
|
+
}
|
33
|
+
/**
|
34
|
+
* Generates a GraphQL query based on the provided options.
|
35
|
+
*
|
36
|
+
* @param opts - Options object for query generation.
|
37
|
+
* @returns The GraphQL query, variables, and current variable counter.
|
38
|
+
*/
|
39
|
+
return function generate(opts) {
|
40
|
+
let varCounter = opts.varCounter || 1;
|
41
|
+
if (!opts || !opts.operation || !opts.table) {
|
42
|
+
throw new Error('❌ operation and table must be specified in options');
|
43
|
+
}
|
44
|
+
const { operation, table } = opts;
|
45
|
+
const where = opts.where || null;
|
46
|
+
const returning = opts.returning || null;
|
47
|
+
const aggregate = opts.aggregate || null;
|
48
|
+
const fragments = opts.fragments || [];
|
49
|
+
const validOperations = ['query', 'subscription', 'insert', 'update', 'delete'];
|
50
|
+
if (!validOperations.includes(operation)) {
|
51
|
+
throw new Error(`❌ Invalid operation type: ${operation}. Allowed types: ${validOperations.join(', ')}`);
|
52
|
+
}
|
53
|
+
let tableName = table;
|
54
|
+
let schemaSection = 'first_level_queries';
|
55
|
+
if (aggregate && operation === 'query') {
|
56
|
+
tableName = `${table}_aggregate`;
|
57
|
+
}
|
58
|
+
if (operation === 'query') {
|
59
|
+
schemaSection = 'first_level_queries';
|
60
|
+
}
|
61
|
+
else if (operation === 'subscription') {
|
62
|
+
schemaSection = 'subscriptions';
|
63
|
+
}
|
64
|
+
else if (['insert', 'update', 'delete'].includes(operation)) {
|
65
|
+
schemaSection = 'mutations';
|
66
|
+
if (operation === 'insert') {
|
67
|
+
tableName = `insert_${table}`;
|
68
|
+
}
|
69
|
+
else if (operation === 'update') {
|
70
|
+
// Handle _by_pk update separately later
|
71
|
+
// tableName = `update_${table}`; // Keep original table for now
|
72
|
+
}
|
73
|
+
else if (operation === 'delete') {
|
74
|
+
// Handle _by_pk delete separately later
|
75
|
+
// tableName = `delete_${table}`; // Keep original table for now
|
76
|
+
}
|
77
|
+
}
|
78
|
+
if (!schema[schemaSection]) {
|
79
|
+
throw new Error(`❌ Schema section ${schemaSection} not found. Schema might be outdated or incorrect.`);
|
80
|
+
}
|
81
|
+
// Special handling for update/delete by pk
|
82
|
+
let isByPkOperation = false;
|
83
|
+
if (['update', 'delete'].includes(operation) && opts.pk_columns) {
|
84
|
+
isByPkOperation = true;
|
85
|
+
tableName = `${operation}_${table}_by_pk`; // e.g., update_users_by_pk
|
86
|
+
}
|
87
|
+
else if (operation === 'query' && opts.pk_columns) {
|
88
|
+
isByPkOperation = true;
|
89
|
+
tableName = `${table}_by_pk`; // e.g., users_by_pk
|
90
|
+
}
|
91
|
+
else if (operation === 'insert' && opts.object && !opts.objects) {
|
92
|
+
// Try to find insert_table_one mutation
|
93
|
+
const oneMutationName = `insert_${table}_one`;
|
94
|
+
if (schema.mutations && schema.mutations[oneMutationName]) {
|
95
|
+
tableName = oneMutationName;
|
96
|
+
isByPkOperation = true; // Treat insert_one like a by_pk operation for simplicity
|
97
|
+
}
|
98
|
+
else {
|
99
|
+
tableName = `insert_${table}`; // Fallback to regular insert
|
100
|
+
}
|
101
|
+
}
|
102
|
+
else if (operation === 'insert') {
|
103
|
+
tableName = `insert_${table}`;
|
104
|
+
}
|
105
|
+
else if (operation === 'update') {
|
106
|
+
tableName = `update_${table}`;
|
107
|
+
}
|
108
|
+
else if (operation === 'delete') {
|
109
|
+
tableName = `delete_${table}`;
|
110
|
+
}
|
111
|
+
// If not by_pk, and it's a query/sub, keep the original table name for non-aggregate
|
112
|
+
else if (['query', 'subscription'].includes(operation) && !aggregate) {
|
113
|
+
tableName = table;
|
114
|
+
}
|
115
|
+
// If it's an aggregate query
|
116
|
+
else if (operation === 'query' && aggregate) {
|
117
|
+
tableName = `${table}_aggregate`;
|
118
|
+
}
|
119
|
+
const possibleQueries = Object.keys(schema[schemaSection]);
|
120
|
+
let queryName = possibleQueries.find(q => q === tableName);
|
121
|
+
// Fallback logic if specific query (like insert_table_one) wasn't found directly
|
122
|
+
if (!queryName) {
|
123
|
+
// General fallback: find first matching query
|
124
|
+
queryName = possibleQueries.find(q => q.includes(table)) || possibleQueries[0];
|
125
|
+
if (!queryName) {
|
126
|
+
throw new Error(`❌ Query/Mutation/Subscription for table "${table}" not found in schema section "${schemaSection}"`);
|
127
|
+
}
|
128
|
+
console.log(`[generator] ⚠️ Could not find exact query name "${tableName}", using fallback "${queryName}"`);
|
129
|
+
}
|
130
|
+
const queryInfo = schema[schemaSection][queryName];
|
131
|
+
if (!queryInfo) {
|
132
|
+
throw new Error(`❌ Query info for "${queryName}" not found in schema section "${schemaSection}"`);
|
133
|
+
}
|
134
|
+
const queryArgs = [];
|
135
|
+
const variables = {};
|
136
|
+
const varParts = [];
|
137
|
+
// Helper function with improved required logic
|
138
|
+
const getGqlType = (argName, argSchema, value, defaultType = 'String', forceRequired = false) => {
|
139
|
+
let typeName = (argSchema === null || argSchema === void 0 ? void 0 : argSchema.type) || defaultType;
|
140
|
+
let isList = (argSchema === null || argSchema === void 0 ? void 0 : argSchema.isList) || false; // Rely more on schema or explicit checks
|
141
|
+
let isRequired = forceRequired || (argSchema === null || argSchema === void 0 ? void 0 : argSchema.isRequired) || false;
|
142
|
+
// Check type name conventions first (e.g., from introspection)
|
143
|
+
if (typeof typeName === 'string') {
|
144
|
+
let baseTypeName = typeName;
|
145
|
+
if (baseTypeName.endsWith('!')) {
|
146
|
+
isRequired = true;
|
147
|
+
baseTypeName = baseTypeName.slice(0, -1);
|
148
|
+
}
|
149
|
+
if (baseTypeName.startsWith('[') && baseTypeName.endsWith(']')) {
|
150
|
+
isList = true;
|
151
|
+
baseTypeName = baseTypeName.slice(1, -1);
|
152
|
+
// Check for inner required type e.g., [String!]
|
153
|
+
if (baseTypeName.endsWith('!')) {
|
154
|
+
// Mark inner as required if needed? (Handled later for known types)
|
155
|
+
baseTypeName = baseTypeName.slice(0, -1);
|
156
|
+
}
|
157
|
+
}
|
158
|
+
typeName = baseTypeName;
|
159
|
+
}
|
160
|
+
// Determine list/required based on arg name conventions
|
161
|
+
const baseTable = table; // Use original table name for type conventions
|
162
|
+
let finalType = typeName;
|
163
|
+
let finalIsRequired = isRequired;
|
164
|
+
let finalIsList = isList;
|
165
|
+
let innerRequired = false;
|
166
|
+
// Apply conventions/overrides
|
167
|
+
if (argName === 'objects') {
|
168
|
+
finalType = `${baseTable}_insert_input`;
|
169
|
+
finalIsList = true;
|
170
|
+
finalIsRequired = true;
|
171
|
+
innerRequired = true;
|
172
|
+
}
|
173
|
+
if (argName === 'object') {
|
174
|
+
finalType = `${baseTable}_insert_input`;
|
175
|
+
finalIsList = false;
|
176
|
+
finalIsRequired = true;
|
177
|
+
}
|
178
|
+
if (argName === 'order_by') {
|
179
|
+
finalType = `${baseTable}_order_by`;
|
180
|
+
finalIsList = true;
|
181
|
+
finalIsRequired = false;
|
182
|
+
innerRequired = true;
|
183
|
+
} // List itself not required, but inner usually is
|
184
|
+
if (argName === 'pk_columns') {
|
185
|
+
finalType = `${baseTable}_pk_columns_input`;
|
186
|
+
finalIsList = false;
|
187
|
+
finalIsRequired = true;
|
188
|
+
}
|
189
|
+
if (argName === '_set') {
|
190
|
+
finalType = `${baseTable}_set_input`;
|
191
|
+
finalIsList = false;
|
192
|
+
finalIsRequired = true;
|
193
|
+
}
|
194
|
+
if (argName === 'where') {
|
195
|
+
finalType = `${baseTable}_bool_exp`;
|
196
|
+
finalIsList = false;
|
197
|
+
finalIsRequired = false;
|
198
|
+
}
|
199
|
+
// If it's a direct PK arg (like `id` in `users_by_pk(id: uuid!)`)
|
200
|
+
if (forceRequired) {
|
201
|
+
finalIsRequired = true;
|
202
|
+
finalIsList = false; // Direct PK args are typically not lists
|
203
|
+
}
|
204
|
+
// Construct the final type string
|
205
|
+
let typeString = finalType;
|
206
|
+
if (finalIsList) {
|
207
|
+
typeString = `[${finalType}${innerRequired ? '!' : ''}]`;
|
208
|
+
}
|
209
|
+
if (finalIsRequired) {
|
210
|
+
typeString += '!';
|
211
|
+
}
|
212
|
+
return typeString;
|
213
|
+
};
|
214
|
+
// Argument processing function (now relies on getGqlType for correctness)
|
215
|
+
const processArg = (argName, value, argSchema, isDirectPk = false) => {
|
216
|
+
if (value === undefined || value === null)
|
217
|
+
return;
|
218
|
+
const varName = `v${varCounter++}`;
|
219
|
+
queryArgs.push(`${argName}: $${varName}`);
|
220
|
+
variables[varName] = value;
|
221
|
+
const gqlType = getGqlType(argName, argSchema, value, 'String', isDirectPk);
|
222
|
+
varParts.push(`$${varName}: ${gqlType}`);
|
223
|
+
};
|
224
|
+
// --- Argument Processing with deterministic order ---
|
225
|
+
const argProcessingOrder = [
|
226
|
+
// Common args first
|
227
|
+
'where',
|
228
|
+
// PK args (direct or pk_columns object)
|
229
|
+
...(isByPkOperation && opts.pk_columns ? Object.keys(opts.pk_columns) : []), // Direct PK args like 'id'
|
230
|
+
'pk_columns', // The pk_columns input object itself
|
231
|
+
// Mutation specific
|
232
|
+
'_set',
|
233
|
+
'objects',
|
234
|
+
'object',
|
235
|
+
// Pagination/Sorting
|
236
|
+
'limit',
|
237
|
+
'offset',
|
238
|
+
'order_by'
|
239
|
+
];
|
240
|
+
const processedArgs = new Set();
|
241
|
+
// Process args in defined order
|
242
|
+
for (const argName of argProcessingOrder) {
|
243
|
+
if (!queryInfo.args || !queryInfo.args[argName])
|
244
|
+
continue; // Skip if arg not in schema
|
245
|
+
if (processedArgs.has(argName))
|
246
|
+
continue;
|
247
|
+
const argSchema = queryInfo.args[argName];
|
248
|
+
let value = undefined;
|
249
|
+
let isDirectPk = false;
|
250
|
+
// Map opts to schema args
|
251
|
+
if (argName === 'pk_columns' && opts.pk_columns) {
|
252
|
+
// Process this ONLY if the operation expects pk_columns (update_by_pk)
|
253
|
+
if (operation === 'update') {
|
254
|
+
value = opts.pk_columns;
|
255
|
+
}
|
256
|
+
else {
|
257
|
+
// For query_by_pk and delete_by_pk, pk_columns is used to find direct args
|
258
|
+
continue; // Skip processing pk_columns itself here
|
259
|
+
}
|
260
|
+
}
|
261
|
+
else if (argName === '_set' && opts._set) {
|
262
|
+
value = opts._set;
|
263
|
+
}
|
264
|
+
else if (argName === 'objects' && (opts.objects || opts.object)) {
|
265
|
+
value = opts.objects || [opts.object];
|
266
|
+
}
|
267
|
+
else if (argName === 'object' && opts.object && !opts.objects) {
|
268
|
+
value = opts.object;
|
269
|
+
}
|
270
|
+
else if (isByPkOperation && opts.pk_columns && opts.pk_columns[argName] !== undefined) {
|
271
|
+
// Handle direct PK arg like `id` for `_by_pk` operations
|
272
|
+
// Check if the schema actually expects this direct arg
|
273
|
+
if (queryInfo.args[argName]) {
|
274
|
+
value = opts.pk_columns[argName];
|
275
|
+
isDirectPk = true;
|
276
|
+
}
|
277
|
+
else {
|
278
|
+
// This direct PK arg is not in schema, maybe it expects pk_columns object?
|
279
|
+
// Let's skip processing it directly if pk_columns object is also in the processing order
|
280
|
+
if (argProcessingOrder.includes('pk_columns'))
|
281
|
+
continue;
|
282
|
+
else
|
283
|
+
value = opts.pk_columns[argName]; // Process if pk_columns object isn't expected
|
284
|
+
}
|
285
|
+
}
|
286
|
+
else if (opts[argName] !== undefined) {
|
287
|
+
value = opts[argName];
|
288
|
+
}
|
289
|
+
if (value !== undefined) {
|
290
|
+
processArg(argName, value, argSchema, isDirectPk);
|
291
|
+
processedArgs.add(argName);
|
292
|
+
}
|
293
|
+
}
|
294
|
+
// Process any remaining args not in the defined order (should be rare)
|
295
|
+
if (queryInfo.args) {
|
296
|
+
for (const argName in queryInfo.args) {
|
297
|
+
if (!processedArgs.has(argName)) {
|
298
|
+
const value = opts[argName];
|
299
|
+
if (value !== undefined) {
|
300
|
+
processArg(argName, value, queryInfo.args[argName], false);
|
301
|
+
processedArgs.add(argName);
|
302
|
+
}
|
303
|
+
}
|
304
|
+
}
|
305
|
+
}
|
306
|
+
// --- End Argument Processing ---
|
307
|
+
const returningFields = [];
|
308
|
+
function processReturningField(field, currentVarCounterRef) {
|
309
|
+
if (typeof field === 'string') {
|
310
|
+
return field.trim();
|
311
|
+
}
|
312
|
+
if (typeof field === 'object' && field !== null) {
|
313
|
+
const fieldName = Object.keys(field)[0];
|
314
|
+
const subFieldsOrParams = field[fieldName];
|
315
|
+
if (typeof subFieldsOrParams === 'boolean' && subFieldsOrParams) {
|
316
|
+
return fieldName;
|
317
|
+
}
|
318
|
+
if (typeof subFieldsOrParams === 'boolean' && !subFieldsOrParams) {
|
319
|
+
return ''; // Explicitly skip false fields
|
320
|
+
}
|
321
|
+
if (Array.isArray(subFieldsOrParams)) {
|
322
|
+
const subFieldsStr = subFieldsOrParams
|
323
|
+
.map(sf => processReturningField(sf, currentVarCounterRef))
|
324
|
+
.filter(Boolean) // Remove empty strings from skipped fields
|
325
|
+
.join('\n ');
|
326
|
+
return subFieldsStr ? `${fieldName} {\n ${subFieldsStr}\n }` : '';
|
327
|
+
}
|
328
|
+
if (typeof subFieldsOrParams === 'string') {
|
329
|
+
return `${fieldName} {\n ${subFieldsOrParams}\n }`;
|
330
|
+
}
|
331
|
+
// Handling nested query object with potential parameters
|
332
|
+
if (typeof subFieldsOrParams === 'object' && subFieldsOrParams !== null) {
|
333
|
+
const { where: nestedWhere, limit: nestedLimit, offset: nestedOffset, order_by: nestedOrderBy, alias, returning: nestedReturningDef } = subFieldsOrParams, otherParams = __rest(subFieldsOrParams, ["where", "limit", "offset", "order_by", "alias", "returning"]);
|
334
|
+
const relationName = fieldName;
|
335
|
+
const fieldAliasOrName = alias || relationName;
|
336
|
+
const relationArgTypeNameBase = alias ? alias : relationName;
|
337
|
+
const nestedArgs = [];
|
338
|
+
// Nested argument processing
|
339
|
+
const processNestedArg = (argName, value, typeSuffix, defaultType = 'String', forceList = false) => {
|
340
|
+
if (value === undefined || value === null)
|
341
|
+
return;
|
342
|
+
const varName = `v${currentVarCounterRef.count++}`;
|
343
|
+
nestedArgs.push(`${argName}: $${varName}`);
|
344
|
+
variables[varName] = value;
|
345
|
+
// Construct type, e.g., users_bool_exp, posts_order_by
|
346
|
+
let gqlType = typeSuffix ? `${relationArgTypeNameBase}${typeSuffix}` : defaultType;
|
347
|
+
let isRequired = false; // Assume nested args aren't required unless schema says so
|
348
|
+
let isList = forceList || (argName === 'order_by'); // Force list for order_by
|
349
|
+
// Basic check if type name implies list/required (might need schema lookup)
|
350
|
+
if (gqlType.startsWith('['))
|
351
|
+
isList = true;
|
352
|
+
if (gqlType.endsWith('!')) {
|
353
|
+
isRequired = true;
|
354
|
+
gqlType = gqlType.slice(0, -1);
|
355
|
+
}
|
356
|
+
// Strip list markers if present, handle wrapping below
|
357
|
+
if (gqlType.startsWith('[') && gqlType.endsWith(']')) {
|
358
|
+
gqlType = gqlType.slice(1, -1);
|
359
|
+
}
|
360
|
+
let finalType = gqlType;
|
361
|
+
if (isList) {
|
362
|
+
// Assume inner type is required for order_by list
|
363
|
+
const innerRequired = argName === 'order_by' ? '!' : '';
|
364
|
+
finalType = `[${gqlType}${innerRequired}]`;
|
365
|
+
// Is the list itself required? (Usually not for nested args)
|
366
|
+
isRequired = false;
|
367
|
+
}
|
368
|
+
varParts.push(`$${varName}: ${finalType}${isRequired ? '!' : ''}`);
|
369
|
+
};
|
370
|
+
processNestedArg('where', nestedWhere, '_bool_exp');
|
371
|
+
processNestedArg('limit', nestedLimit, '', 'Int');
|
372
|
+
processNestedArg('offset', nestedOffset, '', 'Int');
|
373
|
+
// Pass forceList=true for order_by
|
374
|
+
processNestedArg('order_by', nestedOrderBy, '_order_by', 'String', true);
|
375
|
+
// Process other arbitrary parameters
|
376
|
+
for (const paramName in otherParams) {
|
377
|
+
processNestedArg(paramName, otherParams[paramName], ''); // Assume String default
|
378
|
+
}
|
379
|
+
const nestedArgsStr = nestedArgs.length > 0 ? `(${nestedArgs.join(', ')})` : '';
|
380
|
+
let finalNestedReturning = ['id']; // Default returning 'id'
|
381
|
+
if (nestedReturningDef) {
|
382
|
+
if (Array.isArray(nestedReturningDef)) {
|
383
|
+
finalNestedReturning = nestedReturningDef;
|
384
|
+
}
|
385
|
+
else if (typeof nestedReturningDef === 'string') {
|
386
|
+
finalNestedReturning = nestedReturningDef.split(/\s+/).filter(Boolean);
|
387
|
+
}
|
388
|
+
else if (typeof nestedReturningDef === 'object') {
|
389
|
+
// Convert object { field: true, another: {...} } to array ['field', { another: {...} }]
|
390
|
+
finalNestedReturning = Object.entries(nestedReturningDef)
|
391
|
+
.filter(([_, value]) => value) // Filter out false values
|
392
|
+
.map(([key, value]) => (typeof value === 'boolean' ? key : { [key]: value }));
|
393
|
+
}
|
394
|
+
}
|
395
|
+
const nestedFieldsStr = finalNestedReturning
|
396
|
+
.map(f => processReturningField(f, currentVarCounterRef))
|
397
|
+
.filter(Boolean) // Remove empty strings from skipped fields
|
398
|
+
.join('\n ');
|
399
|
+
// Use alias in the field definition if present
|
400
|
+
const fieldDefinition = alias ? `${relationName}: ${fieldAliasOrName}` : fieldAliasOrName;
|
401
|
+
return nestedFieldsStr ? `${fieldDefinition}${nestedArgsStr} {\n ${nestedFieldsStr}\n }` : '';
|
402
|
+
}
|
403
|
+
return ''; // Skip invalid field types
|
404
|
+
}
|
405
|
+
return ''; // Skip invalid field types
|
406
|
+
}
|
407
|
+
const varCounterRef = { count: varCounter }; // Use ref for mutable counter in recursion
|
408
|
+
// ---- START MODIFICATION ----
|
409
|
+
let defaultFieldsGenerated = false;
|
410
|
+
// Function to generate default fields based on operation type and schema
|
411
|
+
const generateDefaultFields = () => {
|
412
|
+
var _a;
|
413
|
+
if (defaultFieldsGenerated)
|
414
|
+
return; // Generate only once
|
415
|
+
if (aggregate) {
|
416
|
+
// Aggregate logic already adds `aggregate { ... }` and potentially `nodes { ... }`
|
417
|
+
// No separate default fields needed here unless `returning` for nodes is omitted
|
418
|
+
// The existing aggregate logic handles the structure.
|
419
|
+
}
|
420
|
+
else if (queryInfo.returning_fields && !isByPkOperation && operation !== 'delete') {
|
421
|
+
// Default fields for query, subscription, insert (non-PK)
|
422
|
+
returningFields.push('id');
|
423
|
+
['name', 'email', 'created_at', 'updated_at'].forEach(f => {
|
424
|
+
if (queryInfo.returning_fields[f])
|
425
|
+
returningFields.push(f);
|
426
|
+
});
|
427
|
+
}
|
428
|
+
else if (isByPkOperation && operation === 'delete') {
|
429
|
+
// Default for delete_by_pk: Try to return PK fields, fallback to id
|
430
|
+
if (opts.pk_columns && queryInfo.returning_fields) {
|
431
|
+
Object.keys(opts.pk_columns).forEach(pkField => {
|
432
|
+
if (queryInfo.returning_fields[pkField]) {
|
433
|
+
returningFields.push(pkField);
|
434
|
+
}
|
435
|
+
});
|
436
|
+
}
|
437
|
+
// If no PK fields were added, push id as fallback
|
438
|
+
if (returningFields.length === 0 && ((_a = queryInfo.returning_fields) === null || _a === void 0 ? void 0 : _a.id)) {
|
439
|
+
returningFields.push('id');
|
440
|
+
}
|
441
|
+
}
|
442
|
+
else { // Default for other mutations _by_pk (update) and query_by_pk
|
443
|
+
if (queryInfo.returning_fields) {
|
444
|
+
returningFields.push('id'); // Default fallback
|
445
|
+
}
|
446
|
+
}
|
447
|
+
defaultFieldsGenerated = true;
|
448
|
+
};
|
449
|
+
// Process returning option
|
450
|
+
if (returning) {
|
451
|
+
if (Array.isArray(returning)) { // Explicit array provided - overrides defaults
|
452
|
+
returning
|
453
|
+
.map(field => processReturningField(field, varCounterRef))
|
454
|
+
.filter(Boolean)
|
455
|
+
.forEach(processedField => returningFields.push(processedField));
|
456
|
+
defaultFieldsGenerated = true; // Mark defaults as handled/overridden
|
457
|
+
}
|
458
|
+
else if (typeof returning === 'string') { // Explicit string provided - overrides defaults
|
459
|
+
returning.split(/\s+/).filter(Boolean)
|
460
|
+
.map(field => processReturningField(field, varCounterRef)) // Process simple strings
|
461
|
+
.filter(Boolean)
|
462
|
+
.forEach(processedField => returningFields.push(processedField));
|
463
|
+
defaultFieldsGenerated = true; // Mark defaults as handled/overridden
|
464
|
+
}
|
465
|
+
else if (typeof returning === 'object' && returning !== null) { // NEW: Object provided - ADD to defaults
|
466
|
+
// 1. Generate default fields first
|
467
|
+
generateDefaultFields();
|
468
|
+
// 2. Process the object as additional relations/fields
|
469
|
+
Object.entries(returning).forEach(([key, value]) => {
|
470
|
+
// Construct the object format processReturningField expects: { relationName: subOptions }
|
471
|
+
const fieldObject = { [key]: value };
|
472
|
+
const processedField = processReturningField(fieldObject, varCounterRef);
|
473
|
+
if (processedField) {
|
474
|
+
// Avoid adding duplicates if default already added it (less likely for relations)
|
475
|
+
if (!returningFields.includes(processedField)) {
|
476
|
+
returningFields.push(processedField);
|
477
|
+
}
|
478
|
+
}
|
479
|
+
});
|
480
|
+
}
|
481
|
+
else {
|
482
|
+
// Invalid returning type? Fallback to defaults.
|
483
|
+
generateDefaultFields();
|
484
|
+
}
|
485
|
+
}
|
486
|
+
else { // returning is null or undefined - Use defaults
|
487
|
+
generateDefaultFields();
|
488
|
+
}
|
489
|
+
// ---- END MODIFICATION ----
|
490
|
+
varCounter = varCounterRef.count; // Update main counter
|
491
|
+
// Adjust structure for bulk mutations (insert, update, delete) vs single (_one, _by_pk)
|
492
|
+
let finalReturningFields = [...returningFields];
|
493
|
+
if (['insert', 'update', 'delete'].includes(operation) && !isByPkOperation) {
|
494
|
+
// Bulk operations usually return affected_rows and a nested 'returning' array
|
495
|
+
const fieldsForReturning = finalReturningFields.filter(f => !f.startsWith('affected_rows')); // Keep existing fields
|
496
|
+
finalReturningFields = ['affected_rows']; // Start with affected_rows
|
497
|
+
if (fieldsForReturning.length > 0) {
|
498
|
+
const returningFieldsStr = fieldsForReturning.join('\n ');
|
499
|
+
finalReturningFields.push(`returning {\n ${returningFieldsStr}\n }`);
|
500
|
+
}
|
501
|
+
}
|
502
|
+
// Ensure single operations (_one, _by_pk) don't have affected_rows unless explicitly asked?
|
503
|
+
// The current logic seems to handle this by default returning fields based on queryInfo
|
504
|
+
// Determine the GraphQL operation type based on the input operation
|
505
|
+
let gqlOperationType;
|
506
|
+
if (operation === 'query') {
|
507
|
+
gqlOperationType = 'query';
|
508
|
+
}
|
509
|
+
else if (operation === 'subscription') {
|
510
|
+
gqlOperationType = 'subscription';
|
511
|
+
}
|
512
|
+
else { // insert, update, delete
|
513
|
+
gqlOperationType = 'mutation';
|
514
|
+
}
|
515
|
+
// Construct operation name (e.g., QueryUsers, MutationInsertUsersOne)
|
516
|
+
const opNamePrefix = gqlOperationType.charAt(0).toUpperCase() + gqlOperationType.slice(1);
|
517
|
+
// Ensure tablePascal handles potential empty parts from split
|
518
|
+
const tablePascal = queryName.split('_').map(part => part ? part.charAt(0).toUpperCase() + part.slice(1) : '').join('');
|
519
|
+
const operationName = `${opNamePrefix}${tablePascal}`;
|
520
|
+
const argsStr = queryArgs.length > 0 ? `(${queryArgs.join(', ')})` : '';
|
521
|
+
const returningStr = finalReturningFields.length > 0 ? finalReturningFields.join('\n ') : (queryInfo.returning_fields ? 'id' : ''); // Fallback to id if possible
|
522
|
+
const fragmentsStr = fragments.length > 0 ? `\n${fragments.join('\n')}` : '';
|
523
|
+
const queryStr = `
|
524
|
+
${gqlOperationType} ${operationName}${varParts.length > 0 ? `(${varParts.join(', ')})` : ''} {
|
525
|
+
${queryName}${argsStr}${returningStr ? ` {
|
526
|
+
${returningStr}
|
527
|
+
}` : ''}
|
528
|
+
}${fragmentsStr}
|
529
|
+
`;
|
530
|
+
try {
|
531
|
+
const gqlQuery = (0, core_1.gql)(queryStr);
|
532
|
+
return {
|
533
|
+
queryString: queryStr,
|
534
|
+
query: gqlQuery,
|
535
|
+
variables,
|
536
|
+
varCounter
|
537
|
+
};
|
538
|
+
}
|
539
|
+
catch (error) {
|
540
|
+
console.error("❌ Error parsing GraphQL query:", error.message);
|
541
|
+
console.error("Generated Query String:", queryStr);
|
542
|
+
console.error("Variables:", JSON.stringify(variables, null, 2));
|
543
|
+
throw new Error(`Failed to parse generated GraphQL query: ${error.message}`);
|
544
|
+
}
|
545
|
+
};
|
546
|
+
}
|
547
|
+
// Export the factory function
|
548
|
+
exports.default = Generator;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
// Export all utilities from the lib directory
|
18
|
+
__exportStar(require("./utils"), exports);
|
19
|
+
__exportStar(require("./apollo"), exports);
|
20
|
+
__exportStar(require("./generator"), exports);
|
@@ -0,0 +1,67 @@
|
|
1
|
+
import { type JWTPayload } from 'jose';
|
2
|
+
/**
|
3
|
+
* Get JWT secret from environment variables (for signing/verifying JWS)
|
4
|
+
* This remains synchronous as it doesn't involve async crypto operations here.
|
5
|
+
* @returns {Uint8Array} Secret key for JWT signing
|
6
|
+
*/
|
7
|
+
export declare const getJwtSecret: () => Uint8Array;
|
8
|
+
/**
|
9
|
+
* Get NextAuth secret from environment variables and hash it using Web Crypto API (SHA-256).
|
10
|
+
* IMPORTANT: This MUST match the NEXTAUTH_SECRET used by next-auth.
|
11
|
+
* @returns {Promise<Uint8Array>} Secret key for JWE operations (always 32 bytes/256 bits)
|
12
|
+
*/
|
13
|
+
export declare const getNextAuthSecret: () => Promise<Uint8Array>;
|
14
|
+
/**
|
15
|
+
* Extracts the algorithm type from JWT secret configuration (for JWS)
|
16
|
+
* This remains synchronous.
|
17
|
+
* @returns {string} The algorithm type (default: 'HS256')
|
18
|
+
*/
|
19
|
+
export declare const getJwtAlgorithm: () => string;
|
20
|
+
/**
|
21
|
+
* Creates a JWT token (JWS) with Hasura claims
|
22
|
+
*
|
23
|
+
* @param {string} userId - User ID
|
24
|
+
* @param {Record<string, any>} [additionalClaims={}] - Additional claims for the token
|
25
|
+
* @param {{ expiresIn?: string }} [options={}] - Options for token generation
|
26
|
+
* @returns {Promise<string>} JWT token (JWS format)
|
27
|
+
*/
|
28
|
+
export declare const generateJWT: (userId: string, additionalClaims?: Record<string, any>, options?: {
|
29
|
+
expiresIn?: string;
|
30
|
+
}) => Promise<string>;
|
31
|
+
/**
|
32
|
+
* Verifies a JWT token (JWS)
|
33
|
+
* @param {string} token - JWT token (JWS format) to verify
|
34
|
+
* @returns {Promise<JWTPayload>} Token payload
|
35
|
+
*/
|
36
|
+
export declare const verifyJWT: (token: string) => Promise<JWTPayload>;
|
37
|
+
/**
|
38
|
+
* Decrypts a NextAuth session token (JWE)
|
39
|
+
* @param {string} sessionToken - The encrypted session token (JWE) from the cookie
|
40
|
+
* @returns {Promise<JWTPayload>} The decrypted payload
|
41
|
+
*/
|
42
|
+
export declare const decryptNextAuthToken: (sessionToken: string) => Promise<JWTPayload>;
|
43
|
+
/**
|
44
|
+
* Extract user ID from a verified/decrypted JWT payload
|
45
|
+
* @param {JWTPayload} payload - The token payload
|
46
|
+
* @returns {string | null} User ID or null if not found
|
47
|
+
*/
|
48
|
+
export declare const getUserIdFromPayload: (payload: JWTPayload) => string | null;
|
49
|
+
/**
|
50
|
+
* Get Hasura claims from a verified/decrypted JWT payload
|
51
|
+
* @param {JWTPayload} payload - The token payload
|
52
|
+
* @returns {Record<string, any> | null} Hasura claims or null if not found
|
53
|
+
*/
|
54
|
+
export declare const getHasuraClaimsFromPayload: (payload: JWTPayload) => Record<string, any> | null;
|
55
|
+
declare const _default: {
|
56
|
+
getJwtSecret: () => Uint8Array;
|
57
|
+
getNextAuthSecret: () => Promise<Uint8Array>;
|
58
|
+
getJwtAlgorithm: () => string;
|
59
|
+
generateJWT: (userId: string, additionalClaims?: Record<string, any>, options?: {
|
60
|
+
expiresIn?: string;
|
61
|
+
}) => Promise<string>;
|
62
|
+
verifyJWT: (token: string) => Promise<JWTPayload>;
|
63
|
+
decryptNextAuthToken: (sessionToken: string) => Promise<JWTPayload>;
|
64
|
+
getUserIdFromPayload: (payload: JWTPayload) => string | null;
|
65
|
+
getHasuraClaimsFromPayload: (payload: JWTPayload) => Record<string, any> | null;
|
66
|
+
};
|
67
|
+
export default _default;
|