@tailor-platform/sdk 2.8.0 → 2.11.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 (50) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/application-B4tCGHiQ.mjs +1 -0
  3. package/dist/{application-D2E3FDfF.mjs → application-CcrP-v7z.mjs} +32 -31
  4. package/dist/application-CcrP-v7z.mjs.map +1 -0
  5. package/dist/cli/lib.mjs +1 -1
  6. package/dist/cli/main.mjs +18 -18
  7. package/dist/cli/main.mjs.map +1 -1
  8. package/dist/cli/shared/seed-context.d.mts +3 -1
  9. package/dist/completion/zsh-worker.zsh +1 -1
  10. package/dist/configure/config/index.d.mts +2 -1
  11. package/dist/configure/index.d.mts +14 -14
  12. package/dist/configure/index.mjs +1 -1
  13. package/dist/configure/index.mjs.map +1 -1
  14. package/dist/configure/services/aigateway/index.d.mts +1 -3
  15. package/dist/configure/services/idp/index.d.mts +1 -1
  16. package/dist/configure/services/resolver/resolver.d.mts +1 -1
  17. package/dist/configure/services/tailordb/schema.d.mts +22 -13
  18. package/dist/configure/types/index.d.mts +1 -1
  19. package/dist/idp-G_ojPBB5.mjs.map +1 -1
  20. package/dist/plugin/builtin/seed/index.mjs +1 -1
  21. package/dist/plugin/types.d.mts +17 -7
  22. package/dist/{register-ts-hook-CQuJ7h5G.mjs → register-ts-hook-YqgUg8P7.mjs} +63 -63
  23. package/dist/register-ts-hook-YqgUg8P7.mjs.map +1 -0
  24. package/dist/{schema-AYG4OhXY.mjs → schema-6d_OHyZf.mjs} +2 -2
  25. package/dist/schema-6d_OHyZf.mjs.map +1 -0
  26. package/dist/{seed-DwqRFdqP.mjs → seed-CMkupmX8.mjs} +41 -17
  27. package/dist/seed-CMkupmX8.mjs.map +1 -0
  28. package/dist/service-BzsSm2f6.mjs +7 -0
  29. package/dist/service-BzsSm2f6.mjs.map +1 -0
  30. package/dist/service-CmwD9bwv.mjs +1 -0
  31. package/dist/types/helpers.d.mts +3 -1
  32. package/dist/vitest/index.d.mts +3 -2
  33. package/dist/vitest/index.mjs +1 -1
  34. package/dist/vitest/index.mjs.map +1 -1
  35. package/dist/vitest/mocks/file.d.mts +1 -1
  36. package/dist/vitest/mocks/tailordb-pglite.d.mts +88 -0
  37. package/dist/vitest/pglite-kysely.d.mts +41 -11
  38. package/docs/plugin/custom.md +95 -0
  39. package/docs/plugin/index.md +5 -0
  40. package/docs/services/tailordb-migration.md +14 -8
  41. package/docs/testing.md +78 -2
  42. package/package.json +9 -9
  43. package/dist/application-D2E3FDfF.mjs.map +0 -1
  44. package/dist/application-rySTKrFa.mjs +0 -1
  45. package/dist/register-ts-hook-CQuJ7h5G.mjs.map +0 -1
  46. package/dist/schema-AYG4OhXY.mjs.map +0 -1
  47. package/dist/seed-DwqRFdqP.mjs.map +0 -1
  48. package/dist/service-COC9whur.mjs +0 -1
  49. package/dist/service-DDon86tM.mjs +0 -7
  50. package/dist/service-DDon86tM.mjs.map +0 -1
@@ -1,6 +1,4 @@
1
- import { AuthNamespaceName } from "../../types/auth-namespace-name.mjs";
2
1
  import { AIGatewayConfig, AIGatewayDefinitionBrand, AIGatewayServiceInput } from "./types.mjs";
3
- import "../../index.mjs";
4
2
  //#region src/configure/services/aigateway/index.d.ts
5
3
  /**
6
4
  * Define an AI Gateway configuration for the Tailor SDK.
@@ -11,7 +9,7 @@ import "../../index.mjs";
11
9
  declare function defineAIGateway(name: string, config: Omit<AIGatewayServiceInput, "name">): {
12
10
  readonly name: string;
13
11
  readonly cors?: string[] | undefined;
14
- readonly authNamespace?: AuthNamespaceName;
12
+ readonly authNamespace?: import("@tailor-platform/sdk").AuthNamespaceName;
15
13
  } & AIGatewayDefinitionBrand;
16
14
  //#endregion
17
15
  export { type AIGatewayConfig, defineAIGateway };
@@ -52,7 +52,7 @@ declare function defineIdp<const TClients extends string[]>(name: string, config
52
52
  requestMfaSettingsUrl?: boolean | undefined;
53
53
  unenrollMfa?: boolean | undefined;
54
54
  } | undefined;
55
- readonly emailConfig?: IdPEmailConfig;
55
+ readonly emailConfig?: import("@tailor-platform/sdk").IdPEmailConfig;
56
56
  readonly clients: TClients;
57
57
  readonly permission?: IdPPermission;
58
58
  } & IdpDefinitionBrand;
@@ -3,8 +3,8 @@ import { InferFieldsOutput, output } from "../../../types/helpers.mjs";
3
3
  import { MachineUserName } from "../auth/types.mjs";
4
4
  import { ResolverInput } from "../../../types/resolver.generated.mjs";
5
5
  import { ResolverPermission } from "./permission.mjs";
6
- import { TailorAnyField, TailorField } from "../../types/type.mjs";
7
6
  import "../../types/machine-user.mjs";
7
+ import { TailorAnyField, TailorField } from "../../types/type.mjs";
8
8
  //#region src/configure/services/resolver/resolver.d.ts
9
9
  type Context<Input extends Record<string, TailorAnyField> | undefined> = {
10
10
  input: Input extends Record<string, TailorAnyField> ? InferFieldsOutput<Input> : never;
@@ -1,10 +1,10 @@
1
1
  import { FieldOptions, FieldOutput, FieldValidateInput, TailorFieldType, TailorToTs } from "../../types/field.types.mjs";
2
2
  import { InferredAttributes } from "../../../runtime/types.mjs";
3
- import { InferFieldsOutput, TypeLevelError, output } from "../../../types/helpers.mjs";
3
+ import { InferFieldsOutput, IsUnion, TypeLevelError, UnionToIntersection, output } from "../../../types/helpers.mjs";
4
4
  import { DBFieldMetadata, DefinedDBFieldMetadata, ExcludeDefaultedDBFields, ExcludeHookedDBFields, ExcludeNestedDBFields, Hook, IndexDef, RelationType, SerialConfig, TailorDBField as TailorDBField$1, TailorDBType as TailorDBType$1, TypeFeatures, TypeHook, TypeValidateFn, UpdateHookFn } from "./types.mjs";
5
5
  import { AllowedValues, AllowedValuesOutput } from "../../types/field.mjs";
6
6
  import { FieldParseArgs } from "../../../runtime/field-parse.mjs";
7
- import { PluginConfigs } from "../../../plugin/types.mjs";
7
+ import { PluginConfigs, PluginFieldExtensions } from "../../../plugin/types.mjs";
8
8
  import { TailorTypeGqlPermission, TailorTypePermission } from "./permission.mjs";
9
9
  import { StandardSchemaV1 } from "@standard-schema/spec";
10
10
  //#region src/configure/services/tailordb/schema.d.ts
@@ -123,6 +123,15 @@ type WithDBTypeMetadata<Defined extends DefinedDBTypeMetadata, Key extends keyof
123
123
  type DBTypeDuplicateInputGuard<Defined extends DefinedDBTypeMetadata, Key extends keyof DefinedDBTypeMetadata, Input, Message extends string> = IsAny<Defined> extends true ? Input : Defined extends Record<Key, unknown> ? TypeLevelError<Message> : Input;
124
124
  type DBTypeDuplicateRestGuard<Defined extends DefinedDBTypeMetadata, Key extends keyof DefinedDBTypeMetadata, Input extends unknown[], Message extends string> = IsAny<Defined> extends true ? Input : Defined extends Record<Key, unknown> ? [TypeLevelError<Message>, ...TypeLevelError<Message>[]] : Input;
125
125
  type FileKeyConflictError<Fields extends Record<string, TailorAnyDBField>, User extends object> = Partial<Record<keyof output<TailorDBType<Fields, User>> & string, TypeLevelError<"file keys cannot use existing field names">>>;
126
+ type PluginFieldExtensionFor<Fields extends Record<string, TailorAnyDBField>, Id extends string, IdConfig> = Id extends keyof PluginFieldExtensions<keyof Fields & string, IdConfig> ? PluginFieldExtensions<keyof Fields & string, IdConfig>[Id] : Record<never, never>;
127
+ type PluginFieldExtensionsUnion<Fields extends Record<string, TailorAnyDBField>, Config extends Record<string, unknown>> = { [Id in keyof Config & string]: PluginFieldExtensionFor<Fields, Id, Config[Id]>; }[keyof Config & string];
128
+ type AllExtensionKeys<Ext> = Ext extends unknown ? keyof Ext : never;
129
+ type PluginFieldExtensionShapeError<Fields extends Record<string, TailorAnyDBField>, Config extends Record<string, unknown>, Id extends string> = PluginFieldExtensionFor<Fields, Id, Config[Id & keyof Config]> extends Record<string, TailorAnyDBField> ? false : true;
130
+ type PluginFieldConflict<Fields extends Record<string, TailorAnyDBField>, Config extends Record<string, unknown>, Id extends string, FileKeys extends string> = [AllExtensionKeys<PluginFieldExtensionFor<Fields, Id, Config[Id & keyof Config]>> & (keyof Fields | FileKeys | AllExtensionKeys<PluginFieldExtensionsUnion<Fields, Omit<Config, Id>>>)] extends [never] ? false : true;
131
+ type PluginConfigExcessProps<Fields extends Record<string, TailorAnyDBField>, Config extends Record<string, unknown>, Id extends string> = Record<Exclude<keyof Config[Id & keyof Config], keyof PluginConfigs<keyof Fields & string>[Id & keyof PluginConfigs<keyof Fields & string>]>, never>;
132
+ type PluginExtendedFields<Fields extends Record<string, TailorAnyDBField>, Config extends Record<string, unknown>> = IsAny<Fields> extends true ? Fields // For `Config = {}`, PluginFieldExtensionsUnion is `never`, and
133
+ : Fields & UnionToIntersection<PluginFieldExtensionsUnion<Fields, Config>>;
134
+ type PluginConfigGuard<Fields extends Record<string, TailorAnyDBField>, Config extends Record<string, unknown>, FileKeys extends string> = IsAny<Fields> extends true ? unknown : { [K in keyof Config]: K extends keyof PluginConfigs<keyof Fields & string> ? IsUnion<Config[K]> extends true ? TypeLevelError<"plugin config must be a single object literal, not a union — assign the config to a variable first if it comes from a conditional expression"> : PluginFieldExtensionShapeError<Fields, Config, K & string> extends true ? TypeLevelError<"PluginFieldExtensions entry must be a Record<string, TailorAnyDBField>"> : PluginFieldConflict<Fields, Config, K & string, FileKeys> extends true ? TypeLevelError<"plugin field extension conflicts with an existing field, a file key declared via .files(), or another plugin's field"> : PluginConfigs<keyof Fields & string>[K] & PluginConfigExcessProps<Fields, Config, K & string> : TypeLevelError<"unknown plugin id">; };
126
135
  type DBFieldDescriptionFn<Defined extends DefinedDBFieldMetadata, Output, Nested extends Record<string, TailorAnyDBField>> = (description: string) => TailorDBField<WithDBFieldDescription<Defined>, Output, Nested>;
127
136
  type DBFieldRelationFn<Defined extends DefinedDBFieldMetadata, Output, Nested extends Record<string, TailorAnyDBField>> = {
128
137
  <S extends RelationType, T extends TailorAnyDBType>(config: RelationConfig<S, T>): TailorDBField<WithDBFieldRelation<Defined, S>, Output, Nested>;
@@ -258,22 +267,22 @@ interface TailorDBField<Defined extends DefinedDBFieldMetadata = DefinedDBFieldM
258
267
  * Full TailorDBType interface with builder methods.
259
268
  * Extends the minimal structural interface from types/ with fluent API methods.
260
269
  */
261
- interface TailorDBType<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributes, Defined extends DefinedDBTypeMetadata = any> extends TailorDBType$1<Fields, User> {
270
+ interface TailorDBType<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributes, Defined extends DefinedDBTypeMetadata = any, FileKeys extends string = never> extends TailorDBType$1<Fields, User> {
262
271
  _description?: string;
263
- hooks(hook: DBTypeDuplicateInputGuard<Defined, "hooks", TypeHook<Fields>, ".hooks() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "hooks">>;
264
- validate(fn: DBTypeDuplicateInputGuard<Defined, "validate", TypeValidateFn<Fields>, ".validate() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "validate">>;
265
- features(features: DBTypeDuplicateInputGuard<Defined, "features", Omit<TypeFeatures, "pluralForm">, ".features() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "features">>;
266
- indexes(...indexes: DBTypeDuplicateRestGuard<Defined, "indexes", IndexDef<TailorDBType<Fields, User, Defined>>[], ".indexes() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "indexes">>;
267
- files<const F extends string>(files: DBTypeDuplicateInputGuard<Defined, "files", Record<F, string> & FileKeyConflictError<Fields, User>, ".files() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "files">>;
268
- permission<U extends object = User, P extends TailorTypePermission<U, output<TailorDBType<Fields, User, Defined>>> = TailorTypePermission<U, output<TailorDBType<Fields, User, Defined>>>>(permission: DBTypeDuplicateInputGuard<Defined, "permission", P, ".permission() has already been set">): TailorDBType<Fields, U, WithDBTypeMetadata<Defined, "permission">>;
269
- gqlPermission<U extends object = User, P extends TailorTypeGqlPermission<U> = TailorTypeGqlPermission<U>>(permission: DBTypeDuplicateInputGuard<Defined, "gqlPermission", P, ".gqlPermission() has already been set">): TailorDBType<Fields, U, WithDBTypeMetadata<Defined, "gqlPermission">>;
270
- description(description: DBTypeDuplicateInputGuard<Defined, "description", string, ".description() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "description">>;
272
+ hooks(hook: DBTypeDuplicateInputGuard<Defined, "hooks", TypeHook<Fields>, ".hooks() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "hooks">, FileKeys>;
273
+ validate(fn: DBTypeDuplicateInputGuard<Defined, "validate", TypeValidateFn<Fields>, ".validate() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "validate">, FileKeys>;
274
+ features(features: DBTypeDuplicateInputGuard<Defined, "features", Omit<TypeFeatures, "pluralForm">, ".features() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "features">, FileKeys>;
275
+ indexes(...indexes: DBTypeDuplicateRestGuard<Defined, "indexes", IndexDef<TailorDBType<Fields, User, Defined, FileKeys>>[], ".indexes() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "indexes">, FileKeys>;
276
+ files<const F extends string>(files: DBTypeDuplicateInputGuard<Defined, "files", Record<F, string> & FileKeyConflictError<Fields, User>, ".files() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "files">, FileKeys | F>;
277
+ permission<U extends object = User, P extends TailorTypePermission<U, output<TailorDBType<Fields, User, Defined>>> = TailorTypePermission<U, output<TailorDBType<Fields, User, Defined>>>>(permission: DBTypeDuplicateInputGuard<Defined, "permission", P, ".permission() has already been set">): TailorDBType<Fields, U, WithDBTypeMetadata<Defined, "permission">, FileKeys>;
278
+ gqlPermission<U extends object = User, P extends TailorTypeGqlPermission<U> = TailorTypeGqlPermission<U>>(permission: DBTypeDuplicateInputGuard<Defined, "gqlPermission", P, ".gqlPermission() has already been set">): TailorDBType<Fields, U, WithDBTypeMetadata<Defined, "gqlPermission">, FileKeys>;
279
+ description(description: DBTypeDuplicateInputGuard<Defined, "description", string, ".description() has already been set">): TailorDBType<Fields, User, WithDBTypeMetadata<Defined, "description">, FileKeys>;
271
280
  pickFields<K extends keyof Fields>(keys: K[]): Pick<Fields, K>;
272
281
  pickFields<K extends keyof Fields, const Opt extends FieldOptions>(keys: K[], options: Opt & DBFieldsCloneOptionsGuard<Fields, K, Opt>): { [P in K]: Fields[P] extends TailorDBField<infer D, infer O> ? TailorDBField<WithDBFieldCloneOptions<D, Opt>, DBFieldCloneOutput<O, Opt>> : never; };
273
282
  omitFields<K extends keyof Fields>(keys: K[]): Omit<Fields, K>;
274
- plugin<P extends keyof PluginConfigs<keyof Fields & string>>(config: { [K in P]: PluginConfigs<keyof Fields & string>[K]; }): TailorDBType<Fields, User, Defined>;
283
+ plugin<const Config extends Record<string, unknown>>(config: Config & PluginConfigGuard<Fields, Config, FileKeys>): TailorDBType<PluginExtendedFields<Fields, Config>, User, Defined, FileKeys>;
275
284
  }
276
- type TailorDBInstance<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributes, Defined extends DefinedDBTypeMetadata = any> = TailorDBType<Fields, User, Defined>;
285
+ type TailorDBInstance<Fields extends Record<string, TailorAnyDBField> = any, User extends object = InferredAttributes, Defined extends DefinedDBTypeMetadata = any, FileKeys extends string = never> = TailorDBType<Fields, User, Defined, FileKeys>;
277
286
  interface RelationConfig<S extends RelationType, T extends TailorDBType> {
278
287
  type: S;
279
288
  toward: {
@@ -1,5 +1,5 @@
1
1
  import { MachineUserName, MachineUserNameRegistry } from "../services/auth/types.mjs";
2
2
  import { AllowedValues, AllowedValuesOutput } from "./field.mjs";
3
- import { TailorAnyField, TailorField } from "./type.mjs";
4
3
  import "./machine-user.mjs";
4
+ import { TailorAnyField, TailorField } from "./type.mjs";
5
5
  export { AllowedValues, AllowedValuesOutput, type MachineUserName, type MachineUserNameRegistry, TailorAnyField, TailorField };
@@ -1 +1 @@
1
- {"version":3,"file":"idp-G_ojPBB5.mjs","names":["#impl"],"sources":["../src/runtime/idp.ts"],"sourcesContent":["/**\n * IDP (Identity Provider) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.idp` runtime API.\n * At runtime this delegates to `globalThis.tailor.idp`. Use `mockIdp` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { idp } from \"@tailor-platform/sdk/runtime\";\n *\n * const client = new idp.Client({ namespace: \"my-namespace\" });\n * const { users } = await client.users({ first: 10 });\n */\n\n/** Configuration object for `idp.Client`. */\nexport interface ClientConfig {\n namespace: string;\n}\n\n/** User record returned by IDP operations. */\nexport interface User {\n id: string;\n name: string;\n disabled: boolean;\n createdAt?: string;\n /**\n * True when the user has at least one enrolled MFA second factor. False when\n * the namespace has MFA disabled or the user has not enrolled a factor.\n */\n mfaEnrolled: boolean;\n /**\n * Enrolled MFA second factor IDs. Pass an entry into\n * `idp.Client.unenrollMfa()` to remove that factor.\n */\n mfaFactorIds: string[];\n}\n\n/** Filter options for `idp.Client.users()`. */\nexport interface UserQuery {\n /** Filter by user IDs */\n ids?: string[];\n /** Filter by user names */\n names?: string[];\n}\n\n/** Pagination/filter options for `idp.Client.users()`. */\nexport interface ListUsersOptions {\n /** Maximum number of users to return */\n first?: number;\n /** Page token for pagination */\n after?: string;\n /** Query filter for users */\n query?: UserQuery;\n}\n\n/** Response shape for `idp.Client.users()`. */\nexport interface ListUsersResponse {\n users: User[];\n nextPageToken: string | null;\n totalCount: number;\n}\n\n/** Input for `idp.Client.createUser()`. */\nexport interface CreateUserInput {\n /** The user's name (typically email) */\n name: string;\n /** The user's password. If omitted, the user is created without a password (cannot log in with any password). */\n password?: string;\n /** Whether the user is disabled */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.updateUser()`. */\nexport interface UpdateUserInput {\n /** The user's ID */\n id: string;\n /** New name for the user */\n name?: string;\n /** New password for the user. Cannot be used with clearPassword. */\n password?: string;\n /** If true, remove the user's password. Cannot be used with password. */\n clearPassword?: boolean;\n /** New disabled status for the user */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.sendPasswordResetEmail()`. */\nexport interface SendPasswordResetEmailInput {\n /** The ID of the user */\n userId: string;\n /** The URI to redirect to after password reset */\n redirectUri: string;\n /** The sender display name. Defaults to 'Tailor Platform IdP'. */\n fromName?: string;\n /** The email subject line. Defaults to the localized default subject. */\n subject?: string;\n}\n\n/** Input for `idp.Client.unenrollMfa()`. */\nexport interface UnenrollMfaInput {\n /** The ID of the user whose factor will be unenrolled. */\n userId: string;\n /**\n * The ID of the factor to unenroll. Factor IDs are exposed on the user\n * record (see {@link User.mfaFactorIds}).\n */\n mfaFactorId: string;\n}\n\n/** Instance methods exposed by `tailor.idp.Client`. */\nexport interface IdpClientInstance {\n users(options?: ListUsersOptions): Promise<ListUsersResponse>;\n user(userId: string): Promise<User>;\n userByName(name: string): Promise<User>;\n createUser(input: CreateUserInput): Promise<User>;\n updateUser(input: UpdateUserInput): Promise<User>;\n deleteUser(userId: string): Promise<boolean>;\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean>;\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean>;\n}\n\n/**\n * Constructor shape for `tailor.idp.Client`.\n * @internal\n */\nexport interface IdpClientConstructor {\n new (config: ClientConfig): IdpClientInstance;\n}\n\n/**\n * Platform API surface for `tailor.idp`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.idp`.\n * @internal\n */\nexport interface TailorIdpAPI {\n Client: IdpClientConstructor;\n}\n\n/**\n * IDP Client for user management operations.\n *\n * Wraps the platform-provided `tailor.idp.Client` and exposes the same surface.\n */\nclass Client {\n #impl: IdpClientInstance;\n\n constructor(config: ClientConfig) {\n this.#impl = new (globalThis as unknown as { tailor: { idp: TailorIdpAPI } }).tailor.idp.Client(\n config,\n );\n }\n\n /**\n * List users in the namespace with optional filtering and pagination.\n * @param options - Pagination and filter options\n * @returns Page of users with `nextPageToken` and `totalCount`\n */\n users(options?: ListUsersOptions): Promise<ListUsersResponse> {\n return this.#impl.users(options);\n }\n\n /**\n * Get a user by ID.\n * @param userId - IDP user ID\n * @returns The matching user\n */\n user(userId: string): Promise<User> {\n return this.#impl.user(userId);\n }\n\n /**\n * Get a user by name.\n * @param name - IDP user name\n * @returns The matching user\n */\n userByName(name: string): Promise<User> {\n return this.#impl.userByName(name);\n }\n\n /**\n * Create a new user.\n * @param input - User attributes\n * @returns The newly created user\n */\n createUser(input: CreateUserInput): Promise<User> {\n return this.#impl.createUser(input);\n }\n\n /**\n * Update an existing user.\n * @param input - User ID plus attributes to update\n * @returns The updated user\n */\n updateUser(input: UpdateUserInput): Promise<User> {\n return this.#impl.updateUser(input);\n }\n\n /**\n * Delete a user by ID.\n * @param userId - IDP user ID\n * @returns `true` when the user was deleted\n */\n deleteUser(userId: string): Promise<boolean> {\n return this.#impl.deleteUser(userId);\n }\n\n /**\n * Send a password reset email to a user.\n * @param input - Target user ID and redirect URI\n * @returns `true` when the email was queued\n */\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean> {\n return this.#impl.sendPasswordResetEmail(input);\n }\n\n /**\n * Unenroll an MFA factor from a user.\n * @param input - Target user ID and factor ID (see {@link User.mfaFactorIds})\n * @returns `true` when the factor was removed\n */\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean> {\n return this.#impl.unenrollMfa(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.idp`. */\nexport const idp: TailorIdpAPI = { Client };\n"],"mappings":"AAkOA,MAAa,EAAoB,CAAE,YApFtB,CACX,GAEA,YAAY,EAAsB,CAChC,KAAKA,GAAQ,IAAK,WAA4D,OAAO,IAAI,OACvF,CACF,CACF,CAOA,MAAM,EAAwD,CAC5D,OAAO,KAAKA,GAAM,MAAM,CAAO,CACjC,CAOA,KAAK,EAA+B,CAClC,OAAO,KAAKA,GAAM,KAAK,CAAM,CAC/B,CAOA,WAAW,EAA6B,CACtC,OAAO,KAAKA,GAAM,WAAW,CAAI,CACnC,CAOA,WAAW,EAAuC,CAChD,OAAO,KAAKA,GAAM,WAAW,CAAK,CACpC,CAOA,WAAW,EAAuC,CAChD,OAAO,KAAKA,GAAM,WAAW,CAAK,CACpC,CAOA,WAAW,EAAkC,CAC3C,OAAO,KAAKA,GAAM,WAAW,CAAM,CACrC,CAOA,uBAAuB,EAAsD,CAC3E,OAAO,KAAKA,GAAM,uBAAuB,CAAK,CAChD,CAOA,YAAY,EAA2C,CACrD,OAAO,KAAKA,GAAM,YAAY,CAAK,CACrC,CACF,CAI0C"}
1
+ {"version":3,"file":"idp-G_ojPBB5.mjs","names":[],"sources":["../src/runtime/idp.ts"],"sourcesContent":["/**\n * IDP (Identity Provider) utilities.\n *\n * Thin typed wrapper around the platform-provided `tailor.idp` runtime API.\n * At runtime this delegates to `globalThis.tailor.idp`. Use `mockIdp` from\n * `@tailor-platform/sdk/vitest` to mock these calls in unit tests.\n * @example\n * import { idp } from \"@tailor-platform/sdk/runtime\";\n *\n * const client = new idp.Client({ namespace: \"my-namespace\" });\n * const { users } = await client.users({ first: 10 });\n */\n\n/** Configuration object for `idp.Client`. */\nexport interface ClientConfig {\n namespace: string;\n}\n\n/** User record returned by IDP operations. */\nexport interface User {\n id: string;\n name: string;\n disabled: boolean;\n createdAt?: string;\n /**\n * True when the user has at least one enrolled MFA second factor. False when\n * the namespace has MFA disabled or the user has not enrolled a factor.\n */\n mfaEnrolled: boolean;\n /**\n * Enrolled MFA second factor IDs. Pass an entry into\n * `idp.Client.unenrollMfa()` to remove that factor.\n */\n mfaFactorIds: string[];\n}\n\n/** Filter options for `idp.Client.users()`. */\nexport interface UserQuery {\n /** Filter by user IDs */\n ids?: string[];\n /** Filter by user names */\n names?: string[];\n}\n\n/** Pagination/filter options for `idp.Client.users()`. */\nexport interface ListUsersOptions {\n /** Maximum number of users to return */\n first?: number;\n /** Page token for pagination */\n after?: string;\n /** Query filter for users */\n query?: UserQuery;\n}\n\n/** Response shape for `idp.Client.users()`. */\nexport interface ListUsersResponse {\n users: User[];\n nextPageToken: string | null;\n totalCount: number;\n}\n\n/** Input for `idp.Client.createUser()`. */\nexport interface CreateUserInput {\n /** The user's name (typically email) */\n name: string;\n /** The user's password. If omitted, the user is created without a password (cannot log in with any password). */\n password?: string;\n /** Whether the user is disabled */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.updateUser()`. */\nexport interface UpdateUserInput {\n /** The user's ID */\n id: string;\n /** New name for the user */\n name?: string;\n /** New password for the user. Cannot be used with clearPassword. */\n password?: string;\n /** If true, remove the user's password. Cannot be used with password. */\n clearPassword?: boolean;\n /** New disabled status for the user */\n disabled?: boolean;\n}\n\n/** Input for `idp.Client.sendPasswordResetEmail()`. */\nexport interface SendPasswordResetEmailInput {\n /** The ID of the user */\n userId: string;\n /** The URI to redirect to after password reset */\n redirectUri: string;\n /** The sender display name. Defaults to 'Tailor Platform IdP'. */\n fromName?: string;\n /** The email subject line. Defaults to the localized default subject. */\n subject?: string;\n}\n\n/** Input for `idp.Client.unenrollMfa()`. */\nexport interface UnenrollMfaInput {\n /** The ID of the user whose factor will be unenrolled. */\n userId: string;\n /**\n * The ID of the factor to unenroll. Factor IDs are exposed on the user\n * record (see {@link User.mfaFactorIds}).\n */\n mfaFactorId: string;\n}\n\n/** Instance methods exposed by `tailor.idp.Client`. */\nexport interface IdpClientInstance {\n users(options?: ListUsersOptions): Promise<ListUsersResponse>;\n user(userId: string): Promise<User>;\n userByName(name: string): Promise<User>;\n createUser(input: CreateUserInput): Promise<User>;\n updateUser(input: UpdateUserInput): Promise<User>;\n deleteUser(userId: string): Promise<boolean>;\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean>;\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean>;\n}\n\n/**\n * Constructor shape for `tailor.idp.Client`.\n * @internal\n */\nexport interface IdpClientConstructor {\n new (config: ClientConfig): IdpClientInstance;\n}\n\n/**\n * Platform API surface for `tailor.idp`. Describes the shape the platform\n * runtime injects on `globalThis.tailor.idp`.\n * @internal\n */\nexport interface TailorIdpAPI {\n Client: IdpClientConstructor;\n}\n\n/**\n * IDP Client for user management operations.\n *\n * Wraps the platform-provided `tailor.idp.Client` and exposes the same surface.\n */\nclass Client {\n #impl: IdpClientInstance;\n\n constructor(config: ClientConfig) {\n this.#impl = new (globalThis as unknown as { tailor: { idp: TailorIdpAPI } }).tailor.idp.Client(\n config,\n );\n }\n\n /**\n * List users in the namespace with optional filtering and pagination.\n * @param options - Pagination and filter options\n * @returns Page of users with `nextPageToken` and `totalCount`\n */\n users(options?: ListUsersOptions): Promise<ListUsersResponse> {\n return this.#impl.users(options);\n }\n\n /**\n * Get a user by ID.\n * @param userId - IDP user ID\n * @returns The matching user\n */\n user(userId: string): Promise<User> {\n return this.#impl.user(userId);\n }\n\n /**\n * Get a user by name.\n * @param name - IDP user name\n * @returns The matching user\n */\n userByName(name: string): Promise<User> {\n return this.#impl.userByName(name);\n }\n\n /**\n * Create a new user.\n * @param input - User attributes\n * @returns The newly created user\n */\n createUser(input: CreateUserInput): Promise<User> {\n return this.#impl.createUser(input);\n }\n\n /**\n * Update an existing user.\n * @param input - User ID plus attributes to update\n * @returns The updated user\n */\n updateUser(input: UpdateUserInput): Promise<User> {\n return this.#impl.updateUser(input);\n }\n\n /**\n * Delete a user by ID.\n * @param userId - IDP user ID\n * @returns `true` when the user was deleted\n */\n deleteUser(userId: string): Promise<boolean> {\n return this.#impl.deleteUser(userId);\n }\n\n /**\n * Send a password reset email to a user.\n * @param input - Target user ID and redirect URI\n * @returns `true` when the email was queued\n */\n sendPasswordResetEmail(input: SendPasswordResetEmailInput): Promise<boolean> {\n return this.#impl.sendPasswordResetEmail(input);\n }\n\n /**\n * Unenroll an MFA factor from a user.\n * @param input - Target user ID and factor ID (see {@link User.mfaFactorIds})\n * @returns `true` when the factor was removed\n */\n unenrollMfa(input: UnenrollMfaInput): Promise<boolean> {\n return this.#impl.unenrollMfa(input);\n }\n}\n\n// Keep the object typed to the public API so the private wrapper class does not leak into d.ts.\n/** Runtime API for `tailor.idp`. */\nexport const idp: TailorIdpAPI = { Client };\n"],"mappings":"AAkOA,MAAa,EAAoB,CAAE,YApFtB,CACX,GAEA,YAAY,EAAsB,CAChC,KAAK,GAAQ,IAAK,WAA4D,OAAO,IAAI,OACvF,CACF,CACF,CAOA,MAAM,EAAwD,CAC5D,OAAO,KAAK,GAAM,MAAM,CAAO,CACjC,CAOA,KAAK,EAA+B,CAClC,OAAO,KAAK,GAAM,KAAK,CAAM,CAC/B,CAOA,WAAW,EAA6B,CACtC,OAAO,KAAK,GAAM,WAAW,CAAI,CACnC,CAOA,WAAW,EAAuC,CAChD,OAAO,KAAK,GAAM,WAAW,CAAK,CACpC,CAOA,WAAW,EAAuC,CAChD,OAAO,KAAK,GAAM,WAAW,CAAK,CACpC,CAOA,WAAW,EAAkC,CAC3C,OAAO,KAAK,GAAM,WAAW,CAAM,CACrC,CAOA,uBAAuB,EAAsD,CAC3E,OAAO,KAAK,GAAM,uBAAuB,CAAK,CAChD,CAOA,YAAY,EAA2C,CACrD,OAAO,KAAK,GAAM,YAAY,CAAK,CACrC,CACF,CAI0C"}
@@ -1 +1 @@
1
- import{n as e,t}from"../../../seed-DwqRFdqP.mjs";export{t as SeedGeneratorID,e as seedPlugin};
1
+ import{n as e,t}from"../../../seed-CMkupmX8.mjs";export{t as SeedGeneratorID,e as seedPlugin};
@@ -119,6 +119,15 @@ type TableConfigRequired<PluginConfig = unknown> = boolean | ((pluginConfig: Plu
119
119
  * Extend this interface via declaration merging to add typed plugin configs.
120
120
  */
121
121
  interface PluginConfigs<Fields extends string = string> {}
122
+ /**
123
+ * Registry mapping a plugin's `id` literal to the fields it injects into the
124
+ * attached table's static type, computed from the literal per-call config
125
+ * passed to `.plugin()`. Extend this interface via declaration merging, keyed
126
+ * by the same `id` used in {@link PluginConfigs}. The value must be a
127
+ * `Record<string, TailorAnyDBField>` of the fields to add — it is merged
128
+ * into the table's existing fields, not a replacement for them.
129
+ */
130
+ interface PluginFieldExtensions<Fields extends string = string, Config = unknown> {}
122
131
  /**
123
132
  * Registry mapping a plugin's `id` literal to its plugin-level config type.
124
133
  * Extend via declaration merging, keyed by the `id` string, from the
@@ -216,34 +225,35 @@ interface PluginGeneratedExecutorLegacy {
216
225
  operation: PluginOperationConfig;
217
226
  }
218
227
  type PluginGeneratedExecutor = PluginGeneratedExecutorWithFile | PluginGeneratedExecutorLegacy;
219
- interface PluginExtends {
220
- fields?: Record<string, TailorAnyDBField>;
228
+ interface PluginExtends<FieldExtension extends Record<string, TailorAnyDBField>> {
229
+ fields?: FieldExtension;
221
230
  }
222
231
  interface PluginOutput {
223
232
  tables?: PluginGeneratedTables;
224
233
  resolvers?: PluginGeneratedResolver[];
225
234
  executors?: PluginGeneratedExecutor[];
226
235
  }
227
- interface TablePluginOutput extends PluginOutput {
228
- extends?: PluginExtends;
236
+ interface TablePluginOutput<FieldExtension extends Record<string, TailorAnyDBField> = Record<string, TailorAnyDBField>> extends PluginOutput {
237
+ extends?: PluginExtends<FieldExtension>;
229
238
  }
230
239
  type NamespacePluginOutput = PluginOutput;
231
240
  /**
232
241
  * Plugin interface that all plugins must implement.
233
242
  * @template TableConfig - Type for per-table configuration passed via .plugin() method
234
243
  * @template PluginConfig - Type for plugin-level configuration passed via definePlugins()
244
+ * @template FieldExtension - Type of the fields injected into the attached table via `extends.fields`. Should match the corresponding {@link PluginFieldExtensions} entry.
235
245
  */
236
- interface Plugin<TableConfig = unknown, PluginConfig = unknown> {
246
+ interface Plugin<TableConfig = unknown, PluginConfig = unknown, FieldExtension extends Record<string, TailorAnyDBField> = Record<string, TailorAnyDBField>> {
237
247
  readonly id: string;
238
248
  readonly description: string;
239
249
  readonly importPath?: string;
240
250
  readonly tableConfigRequired?: TableConfigRequired<PluginConfig>;
241
251
  readonly pluginConfig?: PluginConfig;
242
- onTableLoaded?(context: PluginTableProcessContext<TableConfig, PluginConfig>): TablePluginOutput | Promise<TablePluginOutput>;
252
+ onTableLoaded?(context: PluginTableProcessContext<TableConfig, PluginConfig>): TablePluginOutput<FieldExtension> | Promise<TablePluginOutput<FieldExtension>>;
243
253
  onNamespaceLoaded?(context: PluginNamespaceProcessContext<PluginConfig>): NamespacePluginOutput | Promise<NamespacePluginOutput>;
244
254
  onTailorDBReady?(context: TailorDBReadyContext<PluginConfig>): GeneratorResult | Promise<GeneratorResult>;
245
255
  onResolverReady?(context: ResolverReadyContext<PluginConfig>): GeneratorResult | Promise<GeneratorResult>;
246
256
  onExecutorReady?(context: ExecutorReadyContext<PluginConfig>): GeneratorResult | Promise<GeneratorResult>;
247
257
  }
248
258
  //#endregion
249
- export { ExecutorReadyContext, GeneratorAuthInput, GeneratorResult, NamespacePluginOutput, Plugin, type PluginAttachment, PluginConfigRegistry, PluginConfigs, PluginExecutorContext, PluginExecutorContextBase, PluginGeneratedExecutor, PluginGeneratedExecutorLegacy, PluginGeneratedExecutorWithFile, PluginGeneratedResolver, PluginGeneratedTable, PluginInjectMap, PluginNamespaceProcessContext, PluginOperationConfig, PluginOutput, PluginTableProcessContext, PluginTriggerConfig, ResolverNamespaceData, ResolverReadyContext, TableConfigRequired, TablePluginOutput, TailorDBNamespaceData, TailorDBReadyContext, TailorDBTableForPlugin };
259
+ export { ExecutorReadyContext, GeneratorAuthInput, GeneratorResult, NamespacePluginOutput, Plugin, type PluginAttachment, PluginConfigRegistry, PluginConfigs, PluginExecutorContext, PluginExecutorContextBase, PluginFieldExtensions, PluginGeneratedExecutor, PluginGeneratedExecutorLegacy, PluginGeneratedExecutorWithFile, PluginGeneratedResolver, PluginGeneratedTable, PluginInjectMap, PluginNamespaceProcessContext, PluginOperationConfig, PluginOutput, PluginTableProcessContext, PluginTriggerConfig, ResolverNamespaceData, ResolverReadyContext, TableConfigRequired, TablePluginOutput, TailorDBNamespaceData, TailorDBReadyContext, TailorDBTableForPlugin };