@gaganref/confect-core 10.3.1-fork.9 → 10.3.1-fork.91

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 (94) hide show
  1. package/dist/ActionCall.d.ts +18 -0
  2. package/dist/ActionCall.d.ts.map +1 -0
  3. package/dist/ActionCall.js +21 -0
  4. package/dist/ActionCall.js.map +1 -0
  5. package/dist/App.d.ts +38 -93
  6. package/dist/App.d.ts.map +1 -1
  7. package/dist/App.js +30 -38
  8. package/dist/App.js.map +1 -1
  9. package/dist/Auth.d.ts +33 -9
  10. package/dist/Auth.d.ts.map +1 -1
  11. package/dist/Auth.js +17 -2
  12. package/dist/Auth.js.map +1 -1
  13. package/dist/Callback.d.ts +7 -2
  14. package/dist/Callback.d.ts.map +1 -1
  15. package/dist/Callback.js +11 -6
  16. package/dist/Callback.js.map +1 -1
  17. package/dist/CommitTs.d.ts +18 -0
  18. package/dist/CommitTs.d.ts.map +1 -0
  19. package/dist/CommitTs.js +20 -0
  20. package/dist/CommitTs.js.map +1 -0
  21. package/dist/Component.d.ts +106 -2
  22. package/dist/Component.d.ts.map +1 -1
  23. package/dist/Component.js +44 -18
  24. package/dist/Component.js.map +1 -1
  25. package/dist/FunctionSpec.d.ts +361 -2
  26. package/dist/FunctionSpec.d.ts.map +1 -1
  27. package/dist/FunctionSpec.js +68 -3
  28. package/dist/FunctionSpec.js.map +1 -1
  29. package/dist/GenericId.js +2 -2
  30. package/dist/GroupSpec.js +1 -1
  31. package/dist/Http.d.ts +4 -8
  32. package/dist/Http.d.ts.map +1 -1
  33. package/dist/Http.js +15 -22
  34. package/dist/Http.js.map +1 -1
  35. package/dist/ManifestSection.d.ts +101 -0
  36. package/dist/ManifestSection.d.ts.map +1 -0
  37. package/dist/ManifestSection.js +7 -0
  38. package/dist/ManifestSection.js.map +1 -0
  39. package/dist/Mount.d.ts +200 -0
  40. package/dist/Mount.d.ts.map +1 -0
  41. package/dist/Mount.js +116 -0
  42. package/dist/Mount.js.map +1 -0
  43. package/dist/PaginationError.js +1 -1
  44. package/dist/Profile.d.ts +95 -0
  45. package/dist/Profile.d.ts.map +1 -0
  46. package/dist/Profile.js +15 -0
  47. package/dist/Profile.js.map +1 -0
  48. package/dist/Ref.d.ts +4 -3
  49. package/dist/Ref.d.ts.map +1 -1
  50. package/dist/Ref.js +13 -19
  51. package/dist/Ref.js.map +1 -1
  52. package/dist/RefInternal.d.ts +3 -0
  53. package/dist/RefInternal.d.ts.map +1 -0
  54. package/dist/RefInternal.js +16 -0
  55. package/dist/RefInternal.js.map +1 -0
  56. package/dist/SchemaToValidator.d.ts +20 -6
  57. package/dist/SchemaToValidator.d.ts.map +1 -1
  58. package/dist/SchemaToValidator.js +45 -14
  59. package/dist/SchemaToValidator.js.map +1 -1
  60. package/dist/SystemFields.js +3 -3
  61. package/dist/Table.d.ts +48 -9
  62. package/dist/Table.d.ts.map +1 -1
  63. package/dist/Table.js +41 -13
  64. package/dist/Table.js.map +1 -1
  65. package/dist/index.d.ts +5 -0
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +11 -6
  68. package/dist/internal/annotations.d.ts +2 -0
  69. package/dist/internal/annotations.d.ts.map +1 -0
  70. package/dist/internal/annotations.js +6 -0
  71. package/dist/internal/annotations.js.map +1 -0
  72. package/dist/internal/scalarDocs.d.ts +5 -0
  73. package/dist/internal/scalarDocs.d.ts.map +1 -0
  74. package/dist/internal/scalarDocs.js +43 -0
  75. package/dist/internal/scalarDocs.js.map +1 -0
  76. package/package.json +3 -3
  77. package/src/ActionCall.ts +25 -0
  78. package/src/App.ts +45 -136
  79. package/src/Auth.ts +54 -11
  80. package/src/Callback.ts +17 -4
  81. package/src/CommitTs.ts +26 -0
  82. package/src/Component.ts +204 -11
  83. package/src/FunctionSpec.ts +562 -5
  84. package/src/Http.ts +15 -37
  85. package/src/ManifestSection.ts +108 -0
  86. package/src/Mount.ts +401 -0
  87. package/src/Profile.ts +141 -0
  88. package/src/Ref.ts +19 -26
  89. package/src/RefInternal.ts +26 -0
  90. package/src/SchemaToValidator.ts +97 -22
  91. package/src/Table.ts +157 -23
  92. package/src/index.ts +5 -0
  93. package/src/internal/annotations.ts +1 -0
  94. package/src/internal/scalarDocs.ts +72 -0
package/src/Component.ts CHANGED
@@ -18,6 +18,7 @@ import * as Ref from "./Ref.js";
18
18
  import type * as Refs from "./Refs.js";
19
19
  import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType.js";
20
20
  import * as Spec from "./Spec.js";
21
+ import type * as Table_ from "./Table.js";
21
22
 
22
23
  export class EmptyComponentScopeError extends Data.TaggedError(
23
24
  "EmptyComponentScopeError",
@@ -142,19 +143,100 @@ interface Tree {
142
143
  readonly [key: string]: Tree | Ref.Any;
143
144
  }
144
145
 
146
+ /**
147
+ * Each grouped table's name, mapped to its id field and that id's table.
148
+ */
149
+ export interface GroupMap {
150
+ readonly [table: string]: { readonly key: string; readonly table: string };
151
+ }
152
+
145
153
  export interface Component<
146
154
  Spec_ extends Spec.AnyWithProps,
147
155
  Scope extends IdScope.IdScope,
148
156
  Tables extends string = string,
157
+ Groups_ extends GroupMap = GroupMap,
149
158
  > {
150
159
  readonly [TypeId]: {
151
160
  readonly refs: Tree;
152
161
  readonly scope: Scope;
153
162
  readonly tables: ReadonlyArray<Tables>;
163
+ readonly groups: Groups_;
154
164
  };
155
165
  readonly "~Spec": Spec_;
156
166
  }
157
167
 
168
+ /**
169
+ * A component's tables as `contract` takes them: a table, or the name of a
170
+ * system table.
171
+ */
172
+ export type TableEntry = string | Table_.AnyWithProps;
173
+
174
+ type EntryName<Entry extends TableEntry> = Entry extends string
175
+ ? Entry
176
+ : Entry extends Table_.AnyWithProps
177
+ ? Table_.Name<Entry>
178
+ : never;
179
+
180
+ type Many<A, All = A> = string extends A
181
+ ? true
182
+ : number extends A
183
+ ? true
184
+ : A extends unknown
185
+ ? [All] extends [A]
186
+ ? never
187
+ : true
188
+ : never;
189
+
190
+ type Loose<Entries extends ReadonlyArray<TableEntry>> = true extends
191
+ | Many<Entries>
192
+ | Many<Entries["length"]>
193
+ | { [Index in keyof Entries]: Many<Entries[Index]> }[number]
194
+ ? "pass one table or one name per entry; a union may be absent at runtime"
195
+ : never;
196
+
197
+ type StrayGroup<
198
+ Entries extends ReadonlyArray<TableEntry>,
199
+ Scope extends IdScope.IdScope,
200
+ > = [Loose<Entries>] extends [never]
201
+ ? {
202
+ [Index in keyof Entries]: Entries[Index] extends {
203
+ readonly tableName: infer Name extends string;
204
+ readonly group: Table_.Group<infer Key, infer Target, infer GroupScope>;
205
+ }
206
+ ? [Target, GroupScope] extends [EntryName<Entries[number]>, Scope]
207
+ ? never
208
+ : `${Name}.${Key} is not an id of a table of this component`
209
+ : never;
210
+ }[number]
211
+ : Loose<Entries>;
212
+
213
+ /**
214
+ * The group map `contract` publishes for these table entries.
215
+ */
216
+ export type Groups<Entries extends ReadonlyArray<TableEntry>> = {
217
+ readonly [
218
+ Entry in Extract<
219
+ Entries[number],
220
+ { readonly tableName: string; readonly group: Table_.Group }
221
+ > as Entry["tableName"]
222
+ ]: {
223
+ readonly key: Entry["group"]["key"];
224
+ readonly table: Entry["group"]["table"];
225
+ };
226
+ };
227
+
228
+ /**
229
+ * `unknown` when every entry is one table or name and every group's id names a
230
+ * table of this component in its scope, otherwise an object type naming the
231
+ * refused entry.
232
+ */
233
+ export type CheckGroups<
234
+ Entries extends ReadonlyArray<TableEntry>,
235
+ Scope extends IdScope.IdScope,
236
+ > = [StrayGroup<Entries, Scope>] extends [never]
237
+ ? unknown
238
+ : { readonly "~StrayGroup": StrayGroup<Entries, Scope> };
239
+
158
240
  /**
159
241
  * An opaque identity: its string representation is not part of the API.
160
242
  */
@@ -214,8 +296,22 @@ export type Bound<
214
296
 
215
297
  /**
216
298
  * Build a publishable contract containing only exported functions and codecs.
299
+ * `tables` lists the component's tables, each a table or a system table's name.
300
+ * A table grouped by an id must group by an id of one of these tables.
217
301
  */
218
- export const make = <
302
+ export function contract<
303
+ Spec_ extends Spec.AnyWithProps,
304
+ const Scope extends IdScope.IdScope,
305
+ const Entries extends ReadonlyArray<TableEntry>,
306
+ >(
307
+ spec: Spec_,
308
+ scope: Scope,
309
+ tables: Entries & CheckGroups<Entries, Scope>,
310
+ ): Component<Spec_, Scope, EntryName<Entries[number]>, Groups<Entries>>;
311
+ /**
312
+ * Table names alone, as in an explicit third type argument, carry no groups.
313
+ */
314
+ export function contract<
219
315
  Spec_ extends Spec.AnyWithProps,
220
316
  const Scope extends IdScope.IdScope,
221
317
  const Tables extends string,
@@ -223,7 +319,12 @@ export const make = <
223
319
  spec: Spec_,
224
320
  scope: Scope,
225
321
  tables: ReadonlyArray<Tables>,
226
- ): Component<Spec_, Scope, Tables> => {
322
+ ): Component<Spec_, Scope, Tables, {}>;
323
+ export function contract(
324
+ spec: Spec.AnyWithProps,
325
+ scope: IdScope.IdScope,
326
+ tables: ReadonlyArray<TableEntry>,
327
+ ): Component<Spec.AnyWithProps, IdScope.IdScope> {
227
328
  const specGroups = Spec.groups(spec);
228
329
  Result.getOrThrow(validateContract(scope, specGroups));
229
330
  const collect = (
@@ -251,10 +352,42 @@ export const make = <
251
352
  }),
252
353
  Record.filter((children) => !Record.isEmptyRecord(children)),
253
354
  );
254
- return {
255
- [TypeId]: { refs: collect(specGroups), scope, tables },
256
- } as Component<Spec_, Scope, Tables>;
257
- };
355
+ const grouped: GroupMap = pipe(
356
+ tables,
357
+ Array.flatMap((entry) =>
358
+ typeof entry !== "string" && entry.group !== undefined
359
+ ? [[entry.tableName, entry.group] as const]
360
+ : [],
361
+ ),
362
+ Record.fromEntries,
363
+ );
364
+ const published: Component<
365
+ Spec.AnyWithProps,
366
+ IdScope.IdScope
367
+ >[typeof TypeId] = {
368
+ refs: collect(specGroups),
369
+ scope,
370
+ tables: Array.map(tables, (entry) =>
371
+ typeof entry === "string" ? entry : entry.tableName,
372
+ ),
373
+ groups: grouped,
374
+ };
375
+ return { [TypeId]: published } as Component<
376
+ Spec.AnyWithProps,
377
+ IdScope.IdScope
378
+ >;
379
+ }
380
+
381
+ /**
382
+ * Each grouped table's id field and the table that id names.
383
+ */
384
+ export const groups = <Groups_ extends GroupMap>(
385
+ component: Component<Spec.AnyWithProps, IdScope.IdScope, string, Groups_>,
386
+ ): Groups_ =>
387
+ Record.map(component[TypeId].groups, ({ key, table }) => ({
388
+ key,
389
+ table,
390
+ })) as Groups_;
258
391
 
259
392
  /**
260
393
  * Bind the published contract to an actual installed component reference.
@@ -275,14 +408,14 @@ export const bind = <
275
408
  MountScope<Parent, Extract<MountName<Native>, string | undefined>>,
276
409
  Tables
277
410
  > => {
278
- const contract = component[TypeId];
411
+ const published = component[TypeId];
279
412
  const address = getFunctionAddress(native);
280
413
  const installedReference = Result.getOrThrow(
281
414
  Result.fromNullishOr(
282
415
  address.reference,
283
416
  () =>
284
417
  new UninstalledComponentReferenceError({
285
- definitionScope: contract.scope,
418
+ definitionScope: published.scope,
286
419
  }),
287
420
  ),
288
421
  );
@@ -293,7 +426,7 @@ export const bind = <
293
426
  installedReference,
294
427
  );
295
428
  const rebase = (schema: Schema.ConstraintCodec<any, any, never, never>) =>
296
- GenericId.rebase(schema, contract.scope, scope);
429
+ GenericId.rebase(schema, published.scope, scope);
297
430
  const rebaseMiddleware = memoize(
298
431
  (middleware: MiddlewareSpec.AnyMiddlewareSpec) => {
299
432
  if (!("error" in middleware)) return middleware;
@@ -358,6 +491,8 @@ export const bind = <
358
491
  spec: rebaseMiddleware(attachment.spec),
359
492
  })),
360
493
  nativeRef,
494
+ ref.functionType,
495
+ ref.reservedArgument,
361
496
  );
362
497
  }),
363
498
  Match.exhaustive,
@@ -366,9 +501,9 @@ export const bind = <
366
501
  return visit(child, reference);
367
502
  }
368
503
  });
369
- const refs = visit(contract.refs, native);
504
+ const refs = visit(published.refs, native);
370
505
  Object.defineProperty(refs, BoundTypeId, {
371
- value: { from: contract.scope, scope, tables: contract.tables },
506
+ value: { from: published.scope, scope, tables: published.tables },
372
507
  });
373
508
  return refs as Bound<
374
509
  Spec_,
@@ -416,3 +551,61 @@ export const schema = <
416
551
  component[BoundTypeId].from,
417
552
  component[BoundTypeId].scope,
418
553
  );
554
+
555
+ /**
556
+ * A component's `init`: an internal Confect mutation whose args are the install
557
+ * args each mount passes.
558
+ */
559
+ export type Init = Ref.AnyConfect & {
560
+ readonly "~RuntimeAndFunctionType": RuntimeAndFunctionType.ConvexMutation;
561
+ readonly "~FunctionVisibility": "internal";
562
+ };
563
+
564
+ export interface DescriptorOptions {
565
+ readonly init?: Init;
566
+ /**
567
+ * The component's `_generated/component` contract. A mount of a descriptor
568
+ * with one rebases a callback slot's args with `callbackArgs`.
569
+ */
570
+ readonly contract?: Component<Spec.AnyWithProps, IdScope.IdScope, string>;
571
+ readonly env?: Readonly<Record<string, Schema.Top>>;
572
+ /**
573
+ * The package specifier of the test kit whose `register(t, name)` installs
574
+ * this component and its children under `TestConfect`, such as
575
+ * `"@acme/email/testing"`. Codegen imports it for each mount of the
576
+ * descriptor from another package in place of `<package>/testing` or
577
+ * `<package>/test`. A local component's mount ignores it.
578
+ */
579
+ readonly testing?: string;
580
+ /**
581
+ * Builds the component's client from its native mount, then the mount's
582
+ * `options` when the client takes any.
583
+ */
584
+ readonly client: (...args: never) => unknown;
585
+ }
586
+
587
+ export type Descriptor<
588
+ Name extends string = string,
589
+ Options extends DescriptorOptions = DescriptorOptions,
590
+ > = Options & { readonly name: Name };
591
+
592
+ /**
593
+ * Describe a Convex component for `Mount.make`, as `defineComponent` does for
594
+ * Convex. A component with `init` takes install `args` at each mount, and one
595
+ * with `env` takes `env`. Export it from the package's `./client` entry.
596
+ *
597
+ * ```ts
598
+ * export default Component.make("email", {
599
+ * init: refs.internal.install.init,
600
+ * env: { RESEND_API_KEY: Schema.String },
601
+ * client: Client.make,
602
+ * });
603
+ * ```
604
+ */
605
+ export const make = <
606
+ const Name extends string,
607
+ const Options extends DescriptorOptions,
608
+ >(
609
+ name: Name,
610
+ options: Options,
611
+ ): Descriptor<Name, Options> => ({ ...options, name });