@nxgt/janus-drizzle 0.3.2 → 0.3.3
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 +372 -301
- package/dist/index.js.map +20 -6
- package/dist/relations/context.d.ts +9 -0
- package/dist/relations/context.d.ts.map +1 -0
- package/dist/{relations.d.ts → relations/index.d.ts} +3 -3
- package/dist/relations/index.d.ts.map +1 -0
- package/dist/relations/reads.d.ts +9 -0
- package/dist/relations/reads.d.ts.map +1 -0
- package/dist/relations/tuples.d.ts +12 -0
- package/dist/relations/tuples.d.ts.map +1 -0
- package/dist/relations/writes.d.ts +7 -0
- package/dist/relations/writes.d.ts.map +1 -0
- package/dist/stores/identity-tables.d.ts +5 -0
- package/dist/stores/identity-tables.d.ts.map +1 -0
- package/dist/{stores.d.ts → stores/index.d.ts} +4 -6
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/logins.d.ts +13 -0
- package/dist/stores/logins.d.ts.map +1 -0
- package/dist/stores/records.d.ts +23 -0
- package/dist/stores/records.d.ts.map +1 -0
- package/dist/stores/sessions.d.ts +5 -0
- package/dist/stores/sessions.d.ts.map +1 -0
- package/dist/stores/tokens.d.ts +5 -0
- package/dist/stores/tokens.d.ts.map +1 -0
- package/dist/stores/users.d.ts +5 -0
- package/dist/stores/users.d.ts.map +1 -0
- package/dist/tables/columns.d.ts +22 -0
- package/dist/tables/columns.d.ts.map +1 -0
- package/dist/{tables.d.ts → tables/index.d.ts} +1 -1
- package/dist/tables/index.d.ts.map +1 -0
- package/dist/tables/logins.d.ts +74 -0
- package/dist/tables/logins.d.ts.map +1 -0
- package/dist/tables/relations.d.ts +133 -0
- package/dist/tables/relations.d.ts.map +1 -0
- package/dist/tables/sessions.d.ts +131 -0
- package/dist/tables/sessions.d.ts.map +1 -0
- package/dist/tables/tokens.d.ts +153 -0
- package/dist/tables/tokens.d.ts.map +1 -0
- package/dist/tables/users.d.ts +261 -0
- package/dist/tables/users.d.ts.map +1 -0
- package/package.json +3 -3
- package/dist/relations.d.ts.map +0 -1
- package/dist/stores.d.ts.map +0 -1
- package/dist/tables.d.ts.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/relations.ts", "../src/tables.ts", "../src/translate.ts", "../src/stores.ts", "../src/adapter.ts"],
|
|
3
|
+
"sources": ["../src/tables/index.ts", "../src/tables/logins.ts", "../src/tables/columns.ts", "../src/tables/relations.ts", "../src/tables/sessions.ts", "../src/tables/tokens.ts", "../src/tables/users.ts", "../src/translate.ts", "../src/relations/reads.ts", "../src/relations/tuples.ts", "../src/relations/writes.ts", "../src/relations/index.ts", "../src/stores/sessions.ts", "../src/stores/records.ts", "../src/stores/tokens.ts", "../src/stores/users.ts", "../src/stores/logins.ts", "../src/stores/index.ts", "../src/adapter.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { type
|
|
6
|
-
"import { sql } from 'drizzle-orm';\nimport {\n\tboolean,\n\tcheck,\n\tcustomType,\n\tforeignKey,\n\tindex,\n\tinteger,\n\tjsonb,\n\ttype PgSchema,\n\tpgTable,\n\tprimaryKey,\n\ttext,\n\ttimestamp,\n\tunique,\n} from 'drizzle-orm/pg-core';\n\n/**\n * The five tables, as Drizzle definitions: **your migrations create them**.\n * Export them from the schema file drizzle-kit reads, and `drizzle-kit\n * generate` writes them into your next migration like any table of your own.\n *\n * **The names carry no prefix** — `users`, `logins`, `sessions`, `tokens`,\n * `relations` — because the setup this package recommends is **a database of\n * its own**, backed up and restored on its own. Beside an application's own\n * tables, give them a PostgreSQL schema instead: `{ schema: pgSchema('janus') }`\n * makes them `janus.users` and the rest, and `pg_dump -n janus` backs them up\n * alone.\n *\n * Columns are `snake_case`, as PostgreSQL's own catalog and `@nxgt/drizzle`'s\n * columns are: a camelCase column would have to be quoted in every query\n * written by hand. The records the stores answer are camelCase, as everywhere\n * in Janus.\n *\n * **What the tables hold is the port's record**, field by field. Nothing is\n * encoded, so a row read in `psql` reads like the record in the code.\n */\n\n/** Where the tables live. */\nexport interface JanusTablesOptions {\n\t/**\n\t * A PostgreSQL schema of their own, `pgSchema('janus')`, for a database the\n\t * application's tables share. **Export it from the schema file too**:\n\t * drizzle-kit writes `CREATE SCHEMA` only for a schema it finds exported.\n\t * Absent, the tables are in the connection's `search_path`, `public` by\n\t * default: the database of their own.\n\t */\n\treadonly schema?: PgSchema;\n}\n\n/**\n * A key compared byte by byte, as the port asks (rule 4): `collate \"C\"`. Under\n * a database's default collation, `en_US.UTF-8` or the like, `B` sorts after\n * `a` — and a page in \"ascending id order\" repeats or skips rows.\n */\nconst key = customType<{ data: string; driverData: string }>({\n\tdataType: () => 'text collate \"C\"',\n});\n\n// Millisecond precision: a JavaScript `Date` has no more. At PostgreSQL's\n// default of microseconds, a timestamp written and read back is not the one\n// the core wrote.\nconst at = (name: string) =>\n\ttimestamp(name, { withTimezone: true, precision: 3 });\n\n/**\n * The five tables, in the schema `options` names, or in none.\n *\n * ```ts\n * // src/janus/schema.ts — the schema file of Janus's own drizzle-kit config\n * export const { users, logins, sessions, tokens, relations } = defineJanusTables();\n *\n * // or, in a database the application's tables share\n * export const janus = pgSchema('janus');\n * export const { users, logins, sessions, tokens, relations } = defineJanusTables({ schema: janus });\n * ```\n *\n * Pass what the schema file exports to `createDrizzleAdapter` as `{ tables }`,\n * so the stores query the very tables your migration created.\n */\nexport function defineJanusTables(options: JanusTablesOptions = {}) {\n\tconst { schema } = options;\n\tconst table = (\n\t\tschema === undefined ? pgTable : schema.table\n\t) as typeof pgTable;\n\n\t/**\n\t * Users and their passwords: one row each. `logins` is the port's array,\n\t * verbatim and in order; its uniqueness is `logins`' primary key.\n\t */\n\tconst users = table(\n\t\t'users',\n\t\t{\n\t\t\t/** The UUIDv7 the core minted. `text`, not `uuid`: the store parses nothing. */\n\t\t\tid: key('id').primaryKey(),\n\t\t\ttype: key('type').notNull(),\n\t\t\tschemaVersion: text('schema_version').notNull(),\n\t\t\tactive: boolean('active').notNull(),\n\t\t\t/** The application's fields. The core validated them already. */\n\t\t\tfields: jsonb('fields').notNull(),\n\t\t\tlogins: text('logins').array().notNull(),\n\t\t\tpasswordHash: text('password_hash'),\n\t\t\tpasswordUpdatedAt: at('password_updated_at'),\n\t\t\t/** `'totp'`, or `null` for a user with no second factor. */\n\t\t\tsecondFactorMethod: text('second_factor_method', { enum: ['totp'] }),\n\t\t\t/** Sealed by the core with the application's key: never the plain secret. */\n\t\t\tsecondFactorSecret: text('second_factor_secret'),\n\t\t\tsecondFactorConfirmedAt: at('second_factor_confirmed_at'),\n\t\t\tsecondFactorLastStep: integer('second_factor_last_step'),\n\t\t\temailVerifiedAt: at('email_verified_at'),\n\t\t\tversion: integer('version').notNull(),\n\t\t\tcreatedAt: at('created_at').notNull(),\n\t\t\tupdatedAt: at('updated_at').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\t/** What `logins` references, so a login's type is its user's. */\n\t\t\tunique('users_id_type_unique').on(t.id, t.type),\n\t\t\t/** `listUsers` reads one type in id order. */\n\t\t\tindex('users_type_id').on(t.type, t.id),\n\t\t\t/** A password is a hash and when it was set, or neither. */\n\t\t\tcheck(\n\t\t\t\t'users_password_whole',\n\t\t\t\tsql`(${t.passwordHash} is null) = (${t.passwordUpdatedAt} is null)`,\n\t\t\t),\n\t\t\t/**\n\t\t\t * A second factor is a method and a secret, or neither; its\n\t\t\t * confirmation and last step exist only beside them.\n\t\t\t */\n\t\t\tcheck(\n\t\t\t\t'users_second_factor_whole',\n\t\t\t\tsql`(${t.secondFactorMethod} is null) = (${t.secondFactorSecret} is null) and (${t.secondFactorMethod} is not null or (${t.secondFactorConfirmedAt} is null and ${t.secondFactorLastStep} is null))`,\n\t\t\t),\n\t\t\t/** `'totp'` is the one method; a step counts up from the epoch. */\n\t\t\tcheck(\n\t\t\t\t'users_second_factor_values',\n\t\t\t\tsql`${t.secondFactorMethod} in ('totp') and ${t.secondFactorLastStep} >= 0`,\n\t\t\t),\n\t\t],\n\t);\n\n\t/**\n\t * **The uniqueness of a login, per type** (rule 3): one row per login a\n\t * user holds, and the primary key refuses a second holder. PostgreSQL has\n\t * no unique index over the elements of an array, so this table is that\n\t * index, written in the same transaction as the user. Deleting the user\n\t * deletes its rows.\n\t */\n\tconst logins = table(\n\t\t'logins',\n\t\t{\n\t\t\ttype: key('type').notNull(),\n\t\t\tlogin: key('login').notNull(),\n\t\t\tuserId: key('user_id').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\tprimaryKey({ name: 'logins_pkey', columns: [t.type, t.login] }),\n\t\t\tforeignKey({\n\t\t\t\tname: 'logins_user_fk',\n\t\t\t\tcolumns: [t.userId, t.type],\n\t\t\t\tforeignColumns: [users.id, users.type],\n\t\t\t}).onDelete('cascade'),\n\t\t\tindex('logins_user_id').on(t.userId),\n\t\t],\n\t);\n\n\t/**\n\t * Sessions. No foreign key to the user: deleting a user deletes the user,\n\t * and the core deletes the sessions next — as it does when they live\n\t * elsewhere, in Redis.\n\t */\n\tconst sessions = table(\n\t\t'sessions',\n\t\t{\n\t\t\tid: key('id').primaryKey(),\n\t\t\t/** `sha256` of the session token. The secret itself is never stored. */\n\t\t\ttokenHash: key('token_hash').notNull(),\n\t\t\tuserId: key('user_id').notNull(),\n\t\t\tauthenticatedAt: at('authenticated_at').notNull(),\n\t\t\texpiresAt: at('expires_at').notNull(),\n\t\t\trevokedAt: at('revoked_at'),\n\t\t\tcreatedAt: at('created_at').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\tunique('sessions_token_hash_unique').on(t.tokenHash),\n\t\t\tindex('sessions_user_id').on(t.userId),\n\t\t\t/** `deleteExpiredSessions`: PostgreSQL has no TTL, so the core collects. */\n\t\t\tindex('sessions_expires_at').on(t.expiresAt),\n\t\t],\n\t);\n\n\t/** One-time tokens, keyed by their hash. */\n\tconst tokens = table(\n\t\t'tokens',\n\t\t{\n\t\t\ttokenHash: key('token_hash').primaryKey(),\n\t\t\tkind: text('kind', {\n\t\t\t\tenum: ['verifyEmail', 'resetPassword', 'secondFactor', 'signInCode'],\n\t\t\t}).notNull(),\n\t\t\tuserId: key('user_id').notNull(),\n\t\t\taddress: text('address').notNull(),\n\t\t\t/** A sign-in code's hash, keyed by the token's secret. */\n\t\t\tcodeHash: text('code_hash'),\n\t\t\t/** Codes tried against it. The default fills the rows a migration finds. */\n\t\t\tattempts: integer('attempts').notNull().default(0),\n\t\t\texpiresAt: at('expires_at').notNull(),\n\t\t\tspentAt: at('spent_at'),\n\t\t\tcreatedAt: at('created_at').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\tcheck(\n\t\t\t\t'tokens_kind',\n\t\t\t\tsql`${t.kind} in ('verifyEmail', 'resetPassword', 'secondFactor', 'signInCode')`,\n\t\t\t),\n\t\t\tcheck('tokens_attempts', sql`${t.attempts} >= 0`),\n\t\t\tindex('tokens_user_id').on(t.userId),\n\t\t],\n\t);\n\n\t/**\n\t * Permission tuples, one row each: `record:r1#owners@patient:u1`, or\n\t * `…@team:t1#members` for a subject set, whose `subject_relation` an\n\t * entity's row leaves `null`.\n\t *\n\t * **The uniqueness of a tuple is the unique constraint**, `nulls not\n\t * distinct` so two rows for one entity collide — PostgreSQL 15 or later.\n\t * Its column order is the reverse index `findObjects` pages: every equality\n\t * first, the object id last.\n\t */\n\tconst relations = table(\n\t\t'relations',\n\t\t{\n\t\t\tobjectType: key('object_type').notNull(),\n\t\t\tobjectId: key('object_id').notNull(),\n\t\t\trelation: key('relation').notNull(),\n\t\t\tsubjectType: key('subject_type').notNull(),\n\t\t\tsubjectId: key('subject_id').notNull(),\n\t\t\tsubjectRelation: key('subject_relation'),\n\t\t},\n\t\t(t) => [\n\t\t\tunique('relations_tuple_unique')\n\t\t\t\t.on(\n\t\t\t\t\tt.subjectType,\n\t\t\t\t\tt.subjectId,\n\t\t\t\t\tt.subjectRelation,\n\t\t\t\t\tt.relation,\n\t\t\t\t\tt.objectType,\n\t\t\t\t\tt.objectId,\n\t\t\t\t)\n\t\t\t\t.nullsNotDistinct(),\n\t\t\t/** One hop forwards: `findSubjectSets`, `findEntities`, `deleteEntity` as the object. */\n\t\t\tindex('relations_object').on(t.objectType, t.objectId, t.relation),\n\t\t],\n\t);\n\n\treturn { users, logins, sessions, tokens, relations };\n}\n\n/** The five tables `defineJanusTables` answers. */\nexport type JanusTables = ReturnType<typeof defineJanusTables>;\n\n/**\n * Which tables the stores query: **the ones your schema file exports**, so\n * the migration and the stores cannot disagree. Absent, `defineJanusTables()`:\n * the tables in the connection's `search_path`.\n *\n * ```ts\n * // src/db/schema.ts\n * export const janus = pgSchema('janus');\n * export const janusTables = defineJanusTables({ schema: janus });\n * export const { users, logins, sessions, tokens, relations } = janusTables;\n *\n * // where the adapter is wired\n * const postgres = createDrizzleAdapter(db, { tables: janusTables });\n * ```\n */\nexport interface DrizzleAdapterOptions<\n\tK extends keyof JanusTables = keyof JanusTables,\n> {\n\treadonly tables?: Pick<JanusTables, K>;\n}\n",
|
|
5
|
+
"import { type PgSchema, pgTable } from 'drizzle-orm/pg-core';\nimport type { TableFactory } from './columns';\nimport { loginsTable } from './logins';\nimport { relationsTable } from './relations';\nimport { sessionsTable } from './sessions';\nimport { tokensTable } from './tokens';\nimport { usersTable } from './users';\n\n/**\n * The five tables, as Drizzle definitions: **your migrations create them**.\n * Export them from the schema file drizzle-kit reads, and `drizzle-kit\n * generate` writes them into your next migration like any table of your own.\n *\n * **The names carry no prefix** — `users`, `logins`, `sessions`, `tokens`,\n * `relations` — because the setup this package recommends is **a database of\n * its own**, backed up and restored on its own. Beside an application's own\n * tables, give them a PostgreSQL schema instead: `{ schema: pgSchema('janus') }`\n * makes them `janus.users` and the rest, and `pg_dump -n janus` backs them up\n * alone.\n *\n * Columns are `snake_case`, as PostgreSQL's own catalog and `@nxgt/drizzle`'s\n * columns are: a camelCase column would have to be quoted in every query\n * written by hand. The records the stores answer are camelCase, as everywhere\n * in Janus.\n *\n * **What the tables hold is the port's record**, field by field. Nothing is\n * encoded, so a row read in `psql` reads like the record in the code.\n */\n\n/** Where the tables live. */\nexport interface JanusTablesOptions {\n\t/**\n\t * A PostgreSQL schema of their own, `pgSchema('janus')`, for a database the\n\t * application's tables share. **Export it from the schema file too**:\n\t * drizzle-kit writes `CREATE SCHEMA` only for a schema it finds exported.\n\t * Absent, the tables are in the connection's `search_path`, `public` by\n\t * default: the database of their own.\n\t */\n\treadonly schema?: PgSchema;\n}\n\n/**\n * The five tables, in the schema `options` names, or in none.\n *\n * ```ts\n * // src/janus/schema.ts — the schema file of Janus's own drizzle-kit config\n * export const { users, logins, sessions, tokens, relations } = defineJanusTables();\n *\n * // or, in a database the application's tables share\n * export const janus = pgSchema('janus');\n * export const { users, logins, sessions, tokens, relations } = defineJanusTables({ schema: janus });\n * ```\n *\n * Pass what the schema file exports to `createDrizzleAdapter` as `{ tables }`,\n * so the stores query the very tables your migration created.\n */\nexport function defineJanusTables(options: JanusTablesOptions = {}) {\n\tconst { schema } = options;\n\tconst table = (schema === undefined ? pgTable : schema.table) as TableFactory;\n\tconst users = usersTable(table);\n\tconst logins = loginsTable(table, users);\n\tconst sessions = sessionsTable(table);\n\tconst tokens = tokensTable(table);\n\tconst relations = relationsTable(table);\n\treturn { users, logins, sessions, tokens, relations };\n}\n\n/** The five tables `defineJanusTables` answers. */\nexport type JanusTables = ReturnType<typeof defineJanusTables>;\n\n/**\n * Which tables the stores query: **the ones your schema file exports**, so\n * the migration and the stores cannot disagree. Absent, `defineJanusTables()`:\n * the tables in the connection's `search_path`.\n *\n * ```ts\n * // src/db/schema.ts\n * export const janus = pgSchema('janus');\n * export const janusTables = defineJanusTables({ schema: janus });\n * export const { users, logins, sessions, tokens, relations } = janusTables;\n *\n * // where the adapter is wired\n * const postgres = createDrizzleAdapter(db, { tables: janusTables });\n * ```\n */\nexport interface DrizzleAdapterOptions<\n\tK extends keyof JanusTables = keyof JanusTables,\n> {\n\treadonly tables?: Pick<JanusTables, K>;\n}\n",
|
|
6
|
+
"import { foreignKey, index, primaryKey } from 'drizzle-orm/pg-core';\nimport { key, type TableFactory } from './columns';\nimport type { usersTable } from './users';\n\n/**\n * **The uniqueness of a login, per type** (rule 3): one row per login a\n * user holds, and the primary key refuses a second holder. PostgreSQL has\n * no unique index over the elements of an array, so this table is that\n * index, written in the same transaction as the user. Deleting the user\n * deletes its rows.\n */\nexport function loginsTable(\n\ttable: TableFactory,\n\tusers: ReturnType<typeof usersTable>,\n) {\n\treturn table(\n\t\t'logins',\n\t\t{\n\t\t\ttype: key('type').notNull(),\n\t\t\tlogin: key('login').notNull(),\n\t\t\tuserId: key('user_id').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\tprimaryKey({ name: 'logins_pkey', columns: [t.type, t.login] }),\n\t\t\tforeignKey({\n\t\t\t\tname: 'logins_user_fk',\n\t\t\t\tcolumns: [t.userId, t.type],\n\t\t\t\tforeignColumns: [users.id, users.type],\n\t\t\t}).onDelete('cascade'),\n\t\t\tindex('logins_user_id').on(t.userId),\n\t\t],\n\t);\n}\n",
|
|
7
|
+
"// The building blocks every table is made of: the table factory's type and\n// the column kinds the five tables share.\nimport { customType, type pgTable, timestamp } from 'drizzle-orm/pg-core';\n\n/** `pgTable`, or the `table` of the schema the tables live in. */\nexport type TableFactory = typeof pgTable;\n\n/**\n * A key compared byte by byte, as the port asks (rule 4): `collate \"C\"`. Under\n * a database's default collation, `en_US.UTF-8` or the like, `B` sorts after\n * `a` — and a page in \"ascending id order\" repeats or skips rows.\n */\nexport const key = customType<{ data: string; driverData: string }>({\n\tdataType: () => 'text collate \"C\"',\n});\n\n// Millisecond precision: a JavaScript `Date` has no more. At PostgreSQL's\n// default of microseconds, a timestamp written and read back is not the one\n// the core wrote.\nexport const at = (name: string) =>\n\ttimestamp(name, { withTimezone: true, precision: 3 });\n",
|
|
8
|
+
"import { index, unique } from 'drizzle-orm/pg-core';\nimport { key, type TableFactory } from './columns';\n\n/**\n * Permission tuples, one row each: `record:r1#owners@patient:u1`, or\n * `…@team:t1#members` for a subject set, whose `subject_relation` an\n * entity's row leaves `null`.\n *\n * **The uniqueness of a tuple is the unique constraint**, `nulls not\n * distinct` so two rows for one entity collide — PostgreSQL 15 or later.\n * Its column order is the reverse index `findObjects` pages: every equality\n * first, the object id last.\n */\nexport function relationsTable(table: TableFactory) {\n\treturn table(\n\t\t'relations',\n\t\t{\n\t\t\tobjectType: key('object_type').notNull(),\n\t\t\tobjectId: key('object_id').notNull(),\n\t\t\trelation: key('relation').notNull(),\n\t\t\tsubjectType: key('subject_type').notNull(),\n\t\t\tsubjectId: key('subject_id').notNull(),\n\t\t\tsubjectRelation: key('subject_relation'),\n\t\t},\n\t\t(t) => [\n\t\t\tunique('relations_tuple_unique')\n\t\t\t\t.on(\n\t\t\t\t\tt.subjectType,\n\t\t\t\t\tt.subjectId,\n\t\t\t\t\tt.subjectRelation,\n\t\t\t\t\tt.relation,\n\t\t\t\t\tt.objectType,\n\t\t\t\t\tt.objectId,\n\t\t\t\t)\n\t\t\t\t.nullsNotDistinct(),\n\t\t\t/** One hop forwards: `findSubjectSets`, `findEntities`, `deleteEntity` as the object. */\n\t\t\tindex('relations_object').on(t.objectType, t.objectId, t.relation),\n\t\t],\n\t);\n}\n",
|
|
9
|
+
"import { index, unique } from 'drizzle-orm/pg-core';\nimport { at, key, type TableFactory } from './columns';\n\n/**\n * Sessions. No foreign key to the user: deleting a user deletes the user,\n * and the core deletes the sessions next — as it does when they live\n * elsewhere, in Redis.\n */\nexport function sessionsTable(table: TableFactory) {\n\treturn table(\n\t\t'sessions',\n\t\t{\n\t\t\tid: key('id').primaryKey(),\n\t\t\t/** `sha256` of the session token. The secret itself is never stored. */\n\t\t\ttokenHash: key('token_hash').notNull(),\n\t\t\tuserId: key('user_id').notNull(),\n\t\t\tauthenticatedAt: at('authenticated_at').notNull(),\n\t\t\texpiresAt: at('expires_at').notNull(),\n\t\t\trevokedAt: at('revoked_at'),\n\t\t\tcreatedAt: at('created_at').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\tunique('sessions_token_hash_unique').on(t.tokenHash),\n\t\t\tindex('sessions_user_id').on(t.userId),\n\t\t\t/** `deleteExpiredSessions`: PostgreSQL has no TTL, so the core collects. */\n\t\t\tindex('sessions_expires_at').on(t.expiresAt),\n\t\t],\n\t);\n}\n",
|
|
10
|
+
"import { sql } from 'drizzle-orm';\nimport { check, index, integer, text } from 'drizzle-orm/pg-core';\nimport { at, key, type TableFactory } from './columns';\n\n/** One-time tokens, keyed by their hash. */\nexport function tokensTable(table: TableFactory) {\n\treturn table(\n\t\t'tokens',\n\t\t{\n\t\t\ttokenHash: key('token_hash').primaryKey(),\n\t\t\tkind: text('kind', {\n\t\t\t\tenum: ['verifyEmail', 'resetPassword', 'secondFactor', 'signInCode'],\n\t\t\t}).notNull(),\n\t\t\tuserId: key('user_id').notNull(),\n\t\t\taddress: text('address').notNull(),\n\t\t\t/** A sign-in code's hash, keyed by the token's secret. */\n\t\t\tcodeHash: text('code_hash'),\n\t\t\t/** Codes tried against it. The default fills the rows a migration finds. */\n\t\t\tattempts: integer('attempts').notNull().default(0),\n\t\t\texpiresAt: at('expires_at').notNull(),\n\t\t\tspentAt: at('spent_at'),\n\t\t\tcreatedAt: at('created_at').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\tcheck(\n\t\t\t\t'tokens_kind',\n\t\t\t\tsql`${t.kind} in ('verifyEmail', 'resetPassword', 'secondFactor', 'signInCode')`,\n\t\t\t),\n\t\t\tcheck('tokens_attempts', sql`${t.attempts} >= 0`),\n\t\t\tindex('tokens_user_id').on(t.userId),\n\t\t],\n\t);\n}\n",
|
|
11
|
+
"import { sql } from 'drizzle-orm';\nimport {\n\tboolean,\n\tcheck,\n\tindex,\n\tinteger,\n\tjsonb,\n\ttext,\n\tunique,\n} from 'drizzle-orm/pg-core';\nimport { at, key, type TableFactory } from './columns';\n\n/**\n * Users and their passwords: one row each. `logins` is the port's array,\n * verbatim and in order; its uniqueness is `logins`' primary key.\n */\nexport function usersTable(table: TableFactory) {\n\treturn table(\n\t\t'users',\n\t\t{\n\t\t\t/** The UUIDv7 the core minted. `text`, not `uuid`: the store parses nothing. */\n\t\t\tid: key('id').primaryKey(),\n\t\t\ttype: key('type').notNull(),\n\t\t\tschemaVersion: text('schema_version').notNull(),\n\t\t\tactive: boolean('active').notNull(),\n\t\t\t/** The application's fields. The core validated them already. */\n\t\t\tfields: jsonb('fields').notNull(),\n\t\t\tlogins: text('logins').array().notNull(),\n\t\t\tpasswordHash: text('password_hash'),\n\t\t\tpasswordUpdatedAt: at('password_updated_at'),\n\t\t\t/** `'totp'`, or `null` for a user with no second factor. */\n\t\t\tsecondFactorMethod: text('second_factor_method', { enum: ['totp'] }),\n\t\t\t/** Sealed by the core with the application's key: never the plain secret. */\n\t\t\tsecondFactorSecret: text('second_factor_secret'),\n\t\t\tsecondFactorConfirmedAt: at('second_factor_confirmed_at'),\n\t\t\tsecondFactorLastStep: integer('second_factor_last_step'),\n\t\t\temailVerifiedAt: at('email_verified_at'),\n\t\t\tversion: integer('version').notNull(),\n\t\t\tcreatedAt: at('created_at').notNull(),\n\t\t\tupdatedAt: at('updated_at').notNull(),\n\t\t},\n\t\t(t) => [\n\t\t\t/** What `logins` references, so a login's type is its user's. */\n\t\t\tunique('users_id_type_unique').on(t.id, t.type),\n\t\t\t/** `listUsers` reads one type in id order. */\n\t\t\tindex('users_type_id').on(t.type, t.id),\n\t\t\t/** A password is a hash and when it was set, or neither. */\n\t\t\tcheck(\n\t\t\t\t'users_password_whole',\n\t\t\t\tsql`(${t.passwordHash} is null) = (${t.passwordUpdatedAt} is null)`,\n\t\t\t),\n\t\t\t/**\n\t\t\t * A second factor is a method and a secret, or neither; its\n\t\t\t * confirmation and last step exist only beside them.\n\t\t\t */\n\t\t\tcheck(\n\t\t\t\t'users_second_factor_whole',\n\t\t\t\tsql`(${t.secondFactorMethod} is null) = (${t.secondFactorSecret} is null) and (${t.secondFactorMethod} is not null or (${t.secondFactorConfirmedAt} is null and ${t.secondFactorLastStep} is null))`,\n\t\t\t),\n\t\t\t/** `'totp'` is the one method; a step counts up from the epoch. */\n\t\t\tcheck(\n\t\t\t\t'users_second_factor_values',\n\t\t\t\tsql`${t.secondFactorMethod} in ('totp') and ${t.secondFactorLastStep} >= 0`,\n\t\t\t),\n\t\t],\n\t);\n}\n",
|
|
7
12
|
"import { toDataError } from '@nxgt/drizzle';\nimport { JanusError, StoreConflict, StoreFailure } from '@nxgt/janus';\n\n/**\n * **The database's errors, as the port's.** One file, and one default.\n *\n * | What happens | Becomes |\n * | --- | --- |\n * | A login another user of the type holds | `StoreConflict('login')`, carrying `login` and `userType` |\n * | A row with this id already there | nothing: the insert is a retry, and answers what is stored |\n * | A unique violation on **any other constraint** | **`StoreFailure`** |\n * | A check or foreign key refusing a row | **`StoreFailure`** |\n * | Anything else, absolutely | `StoreFailure`, with `@nxgt/drizzle`'s `DataError` as `cause` |\n *\n * The first two are never errors here: a login is written with `on conflict\n * do nothing`, and a login the statement did not write is one somebody else\n * holds — so no conflict is ever told apart by parsing a driver's message.\n *\n * The bold rows go against the obvious reading. A violation the adapter did\n * not mean to cause is an adapter bug, and reporting it as `LOGIN_TAKEN`\n * would tell somebody their login is taken when it is not. The core\n * validated every record before it reached a store, so a constraint refusing\n * one means the adapter and the port disagree — never the caller's fault.\n *\n * **The default is a failure, not an absence.** That branch is what keeps the\n * port's first rule: nothing here answers `null` for an error.\n */\n\nexport type Slot = 'users' | 'sessions' | 'tokens' | 'relations';\n\n/** Runs one port method, and makes every rejection one the port allows. */\nexport async function run<T>(\n\tslot: Slot,\n\toperation: string,\n\tbody: () => Promise<T>,\n): Promise<T> {\n\ttry {\n\t\treturn await body();\n\t} catch (error) {\n\t\t// Already the port's — a conflict, a NOT_FOUND after a read.\n\t\tif (error instanceof JanusError) throw error;\n\t\tthrow new StoreFailure(`${slot}.${operation}: the store could not answer`, {\n\t\t\tslot,\n\t\t\toperation,\n\t\t\tcause: toDataError(error),\n\t\t});\n\t}\n}\n\n/** The refusal the port promises for a taken login. */\nexport function loginTaken(\n\toperation: string,\n\ttype: string,\n\tlogin: string,\n): StoreConflict {\n\treturn new StoreConflict(\n\t\t'login',\n\t\t`${operation}: the login is taken by another ${type}`,\n\t\t{ login, userType: type, operation },\n\t);\n}\n",
|
|
8
|
-
"import { type PgDatabase, withTransaction } from '@nxgt/drizzle/pg';\nimport type {\n\tId,\n\tJanusStores,\n\tSessionRecord,\n\tSessionStore,\n\tTokenStore,\n\tUserPatch,\n\tUserRecord,\n\tUserStore,\n} from '@nxgt/janus';\nimport { NotFoundError, StoreConflict } from '@nxgt/janus';\nimport { and, asc, eq, gt, isNull, lte, ne, type SQL, sql } from 'drizzle-orm';\nimport {\n\ttype DrizzleAdapterOptions,\n\tdefineJanusTables,\n\ttype JanusTables,\n} from './tables';\nimport { loginTaken, run } from './translate';\n\ntype UserRow = JanusTables['users']['$inferSelect'];\ntype UserInsert = JanusTables['users']['$inferInsert'];\ntype SessionRow = JanusTables['sessions']['$inferSelect'];\n\n/** The four tables the identity stores query. */\ntype IdentityTable = 'users' | 'logins' | 'sessions' | 'tokens';\ntype IdentityTables = Pick<JanusTables, IdentityTable>;\n\n/**\n * The three stores `janus()` takes, over one PostgreSQL database through\n * Drizzle.\n *\n * ```ts\n * const db = drizzle(process.env.DATABASE_URL);\n * const auth = janus({ user, password: { login: 'email' }, store: createDrizzleStores(db), hasher });\n * ```\n *\n * **Every read is one statement**, whose absence is an empty result, turned\n * into `null` here; everything that arrives as a rejection is a failure. There\n * is no path on which an absence and an outage travel the same channel.\n *\n * **A user is written in one transaction** with its logins, whose table holds\n * their uniqueness — `@nxgt/drizzle`'s `withTransaction`, inside the method,\n * as rule 5 allows. Every other write is one statement.\n *\n * `sessions.deleteExpiredSessions` is implemented: PostgreSQL has no TTL, so\n * `auth.collectExpired()` is how lapsed sessions leave the table.\n *\n * `{ tables }` is what your schema file exports; absent, the tables in the\n * connection's `search_path`.\n */\nexport function createDrizzleStores(\n\tdb: PgDatabase,\n\toptions: DrizzleAdapterOptions<IdentityTable> = {},\n): JanusStores {\n\tconst tables = options.tables ?? defineJanusTables();\n\treturn {\n\t\tusers: userStore(db, tables),\n\t\tsessions: sessionStore(db, tables),\n\t\ttokens: tokenStore(db, tables),\n\t};\n}\n\nfunction userStore(db: PgDatabase, tables: IdentityTables): UserStore {\n\tconst run$ = <T>(operation: string, body: () => Promise<T>) =>\n\t\trun('users', operation, body);\n\n\tconst find = async (id: string) => {\n\t\tconst [row] = await db\n\t\t\t.select()\n\t\t\t.from(tables.users)\n\t\t\t.where(eq(tables.users.id, id));\n\t\treturn row === undefined ? null : toUser(row);\n\t};\n\n\t/**\n\t * Writes the logins of one user, and throws the port's conflict for the\n\t * first one another user of the type holds. `on conflict do nothing`: a\n\t * login the statement did not write is one somebody else holds, and a\n\t * concurrent sign-up waits for the first to commit, then writes nothing.\n\t */\n\tconst claim = async (\n\t\ttx: PgDatabase,\n\t\toperation: string,\n\t\tuser: { readonly id: string; readonly type: string },\n\t\tlogins: readonly string[],\n\t) => {\n\t\t// Sorted: two transactions claiming the same logins take their locks in\n\t\t// one order, and never deadlock — the loser waits, then finds them taken.\n\t\tconst distinct = [...new Set(logins)].sort();\n\t\tif (distinct.length === 0) return;\n\t\tconst written = await tx\n\t\t\t.insert(tables.logins)\n\t\t\t.values(\n\t\t\t\tdistinct.map((login) => ({ type: user.type, login, userId: user.id })),\n\t\t\t)\n\t\t\t.onConflictDoNothing()\n\t\t\t.returning({ login: tables.logins.login });\n\t\tif (written.length === distinct.length) return;\n\t\tconst claimed = new Set(written.map((row) => row.login));\n\t\tconst taken = distinct.find((login) => !claimed.has(login)) ?? '';\n\t\tthrow loginTaken(operation, user.type, taken);\n\t};\n\n\treturn {\n\t\tinsertUser: (record) =>\n\t\t\trun$('insertUser', async () => {\n\t\t\t\tconst inserted = await withTransaction(db, async (tx) => {\n\t\t\t\t\tconst [row] = await tx\n\t\t\t\t\t\t.insert(tables.users)\n\t\t\t\t\t\t.values(toUserRow(record))\n\t\t\t\t\t\t.onConflictDoNothing({ target: tables.users.id })\n\t\t\t\t\t\t.returning();\n\t\t\t\t\tif (row === undefined) return null;\n\t\t\t\t\tawait claim(tx, 'insertUser', record, record.logins);\n\t\t\t\t\treturn toUser(row);\n\t\t\t\t});\n\t\t\t\tif (inserted !== null) return inserted;\n\n\t\t\t\t// A retry whose first attempt landed: the user with this id is\n\t\t\t\t// there, and is the answer — logins included, which are theirs.\n\t\t\t\tconst stored = await find(record.id);\n\t\t\t\tif (stored !== null) return stored;\n\t\t\t\t// Deleted between the two statements: a retry of nothing.\n\t\t\t\tthrow new NotFoundError('insertUser: the user was deleted meanwhile', {\n\t\t\t\t\tuserId: record.id,\n\t\t\t\t\toperation: 'insertUser',\n\t\t\t\t});\n\t\t\t}),\n\n\t\tfindUser: (id) => run$('findUser', () => find(id)),\n\n\t\tfindUserByLogin: (type, login) =>\n\t\t\trun$('findUserByLogin', async () => {\n\t\t\t\tconst [row] = await db\n\t\t\t\t\t.select({ user: tables.users })\n\t\t\t\t\t.from(tables.logins)\n\t\t\t\t\t.innerJoin(tables.users, eq(tables.users.id, tables.logins.userId))\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(eq(tables.logins.type, type), eq(tables.logins.login, login)),\n\t\t\t\t\t);\n\t\t\t\treturn row === undefined ? null : toUser(row.user);\n\t\t\t}),\n\n\t\tlistUsers: ({ type, after, limit }) =>\n\t\t\trun$('listUsers', async () => {\n\t\t\t\t// One more than the page, to know whether another follows.\n\t\t\t\tconst found = await db\n\t\t\t\t\t.select()\n\t\t\t\t\t.from(tables.users)\n\t\t\t\t\t.where(\n\t\t\t\t\t\tafter === null\n\t\t\t\t\t\t\t? eq(tables.users.type, type)\n\t\t\t\t\t\t\t: and(eq(tables.users.type, type), gt(tables.users.id, after)),\n\t\t\t\t\t)\n\t\t\t\t\t.orderBy(asc(tables.users.id))\n\t\t\t\t\t.limit(limit + 1);\n\t\t\t\tconst items = found.slice(0, limit).map(toUser);\n\t\t\t\tconst last = items.at(-1);\n\t\t\t\treturn {\n\t\t\t\t\titems,\n\t\t\t\t\tnextCursor:\n\t\t\t\t\t\tfound.length > limit && last !== undefined ? last.id : null,\n\t\t\t\t};\n\t\t\t}),\n\n\t\tupdateUser: (id, patch, ifVersion) =>\n\t\t\trun$('updateUser', () =>\n\t\t\t\twithTransaction(db, async (tx) => {\n\t\t\t\t\tconst [row] = await tx\n\t\t\t\t\t\t.update(tables.users)\n\t\t\t\t\t\t.set({\n\t\t\t\t\t\t\t...toUserSet(patch),\n\t\t\t\t\t\t\tversion: sql`${tables.users.version} + 1`,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.where(\n\t\t\t\t\t\t\tand(eq(tables.users.id, id), eq(tables.users.version, ifVersion)),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.returning();\n\n\t\t\t\t\tif (row === undefined) {\n\t\t\t\t\t\t// The write matched nothing, which alone cannot tell an unknown\n\t\t\t\t\t\t// id from a moved version: read again, and say which.\n\t\t\t\t\t\tconst [stored] = await tx\n\t\t\t\t\t\t\t.select({ version: tables.users.version })\n\t\t\t\t\t\t\t.from(tables.users)\n\t\t\t\t\t\t\t.where(eq(tables.users.id, id));\n\t\t\t\t\t\tif (stored === undefined) {\n\t\t\t\t\t\t\tthrow new NotFoundError('updateUser: no user has this id', {\n\t\t\t\t\t\t\t\tuserId: id,\n\t\t\t\t\t\t\t\toperation: 'updateUser',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow new StoreConflict(\n\t\t\t\t\t\t\t'version',\n\t\t\t\t\t\t\t`updateUser: expected version ${ifVersion}, found ${stored.version}`,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuserId: id,\n\t\t\t\t\t\t\t\texpectedVersion: ifVersion,\n\t\t\t\t\t\t\t\tactualVersion: stored.version,\n\t\t\t\t\t\t\t\toperation: 'updateUser',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (patch.logins !== undefined) {\n\t\t\t\t\t\tawait tx.delete(tables.logins).where(eq(tables.logins.userId, id));\n\t\t\t\t\t\tawait claim(tx, 'updateUser', row, patch.logins);\n\t\t\t\t\t}\n\t\t\t\t\treturn toUser(row);\n\t\t\t\t}),\n\t\t\t),\n\n\t\tdeleteUser: (id) =>\n\t\t\trun$('deleteUser', async () => {\n\t\t\t\t// The logins go with it: their foreign key cascades.\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.users)\n\t\t\t\t\t.where(eq(tables.users.id, id))\n\t\t\t\t\t.returning({ id: tables.users.id });\n\t\t\t\treturn deleted.length === 1;\n\t\t\t}),\n\t};\n}\n\nfunction sessionStore(db: PgDatabase, tables: IdentityTables): SessionStore {\n\tconst run$ = <T>(operation: string, body: () => Promise<T>) =>\n\t\trun('sessions', operation, body);\n\n\treturn {\n\t\tinsertSession: (record) =>\n\t\t\trun$('insertSession', async () => {\n\t\t\t\t// Idempotent under retry: a session with this id is already there.\n\t\t\t\t// A collision on the token hash is not a retry, and fails.\n\t\t\t\tawait db\n\t\t\t\t\t.insert(tables.sessions)\n\t\t\t\t\t.values(record)\n\t\t\t\t\t.onConflictDoNothing({ target: tables.sessions.id });\n\t\t\t}),\n\n\t\tfindSessionByTokenHash: (tokenHash) =>\n\t\t\trun$('findSessionByTokenHash', async () => {\n\t\t\t\tconst [row] = await db\n\t\t\t\t\t.select()\n\t\t\t\t\t.from(tables.sessions)\n\t\t\t\t\t.where(eq(tables.sessions.tokenHash, tokenHash));\n\t\t\t\treturn row === undefined ? null : toSession(row);\n\t\t\t}),\n\n\t\textendSession: (id, expiresAt) =>\n\t\t\trun$('extendSession', async () => {\n\t\t\t\t// `revoked_at is null` in the condition: an extension racing a\n\t\t\t\t// revocation matches nothing, and never brings the session back.\n\t\t\t\tconst [row] = await db\n\t\t\t\t\t.update(tables.sessions)\n\t\t\t\t\t.set({ expiresAt })\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(eq(tables.sessions.id, id), isNull(tables.sessions.revokedAt)),\n\t\t\t\t\t)\n\t\t\t\t\t.returning();\n\t\t\t\treturn row === undefined ? null : toSession(row);\n\t\t\t}),\n\n\t\trevokeSession: (id, at) =>\n\t\t\trun$('revokeSession', async () => {\n\t\t\t\t// `coalesce`, so a session already revoked keeps its first\n\t\t\t\t// `revokedAt` and still counts as matched.\n\t\t\t\tconst matched = await db\n\t\t\t\t\t.update(tables.sessions)\n\t\t\t\t\t.set({\n\t\t\t\t\t\trevokedAt: sql`coalesce(${tables.sessions.revokedAt}, ${stamp(at)})`,\n\t\t\t\t\t})\n\t\t\t\t\t.where(eq(tables.sessions.id, id))\n\t\t\t\t\t.returning({ id: tables.sessions.id });\n\t\t\t\treturn matched.length === 1;\n\t\t\t}),\n\n\t\trevokeUserSessions: (userId, at, except) =>\n\t\t\trun$('revokeUserSessions', async () => {\n\t\t\t\tconst standing = and(\n\t\t\t\t\teq(tables.sessions.userId, userId),\n\t\t\t\t\tisNull(tables.sessions.revokedAt),\n\t\t\t\t);\n\t\t\t\tconst revoked = await db\n\t\t\t\t\t.update(tables.sessions)\n\t\t\t\t\t.set({ revokedAt: at })\n\t\t\t\t\t.where(\n\t\t\t\t\t\texcept === undefined\n\t\t\t\t\t\t\t? standing\n\t\t\t\t\t\t\t: and(standing, ne(tables.sessions.id, except)),\n\t\t\t\t\t)\n\t\t\t\t\t.returning({ id: tables.sessions.id });\n\t\t\t\treturn revoked.length;\n\t\t\t}),\n\n\t\tdeleteUserSessions: (userId) =>\n\t\t\trun$('deleteUserSessions', async () => {\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.sessions)\n\t\t\t\t\t.where(eq(tables.sessions.userId, userId))\n\t\t\t\t\t.returning({ id: tables.sessions.id });\n\t\t\t\treturn deleted.length;\n\t\t\t}),\n\n\t\tdeleteExpiredSessions: (before) =>\n\t\t\trun$('deleteExpiredSessions', async () => {\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.sessions)\n\t\t\t\t\t.where(lte(tables.sessions.expiresAt, before))\n\t\t\t\t\t.returning({ id: tables.sessions.id });\n\t\t\t\treturn deleted.length;\n\t\t\t}),\n\t};\n}\n\nfunction tokenStore(db: PgDatabase, tables: IdentityTables): TokenStore {\n\tconst run$ = <T>(operation: string, body: () => Promise<T>) =>\n\t\trun('tokens', operation, body);\n\n\treturn {\n\t\tinsertToken: (record) =>\n\t\t\trun$('insertToken', async () => {\n\t\t\t\t// The hash is the key: a collision is a retry.\n\t\t\t\tawait db.insert(tables.tokens).values(record).onConflictDoNothing();\n\t\t\t}),\n\n\t\tconsumeToken: (tokenHash, kind, at) =>\n\t\t\trun$('consumeToken', async () => {\n\t\t\t\t// **One conditional write**, answering the row as it was before\n\t\t\t\t// it. `for update` makes a concurrent call wait for this one and\n\t\t\t\t// then read the spent row, so exactly one caller ever reads\n\t\t\t\t// `spentAt: null`; `coalesce` keeps a first `spentAt`.\n\t\t\t\tconst before = db.$with('before').as(\n\t\t\t\t\tdb\n\t\t\t\t\t\t.select()\n\t\t\t\t\t\t.from(tables.tokens)\n\t\t\t\t\t\t.where(\n\t\t\t\t\t\t\tand(\n\t\t\t\t\t\t\t\teq(tables.tokens.tokenHash, tokenHash),\n\t\t\t\t\t\t\t\teq(tables.tokens.kind, kind),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.for('update'),\n\t\t\t\t);\n\t\t\t\tconst [spent] = await db\n\t\t\t\t\t.with(before)\n\t\t\t\t\t.update(tables.tokens)\n\t\t\t\t\t.set({\n\t\t\t\t\t\tspentAt: sql`coalesce(${tables.tokens.spentAt}, ${stamp(at)})`,\n\t\t\t\t\t})\n\t\t\t\t\t.from(before)\n\t\t\t\t\t.where(eq(tables.tokens.tokenHash, before.tokenHash))\n\t\t\t\t\t.returning({\n\t\t\t\t\t\ttokenHash: before.tokenHash,\n\t\t\t\t\t\tkind: before.kind,\n\t\t\t\t\t\tuserId: before.userId,\n\t\t\t\t\t\taddress: before.address,\n\t\t\t\t\t\tcodeHash: before.codeHash,\n\t\t\t\t\t\tattempts: before.attempts,\n\t\t\t\t\t\texpiresAt: before.expiresAt,\n\t\t\t\t\t\tspentAt: before.spentAt,\n\t\t\t\t\t\tcreatedAt: before.createdAt,\n\t\t\t\t\t});\n\t\t\t\treturn spent === undefined\n\t\t\t\t\t? null\n\t\t\t\t\t: { ...spent, userId: spent.userId as Id };\n\t\t\t}),\n\n\t\tcountAttempt: (tokenHash, kind) =>\n\t\t\trun$('countAttempt', async () => {\n\t\t\t\t// **One conditional write**: `attempts + 1` on the row, under the\n\t\t\t\t// row's lock, so twenty concurrent calls answer twenty counts. A\n\t\t\t\t// spent token matches nothing here, and is read as it is below.\n\t\t\t\tconst match = and(\n\t\t\t\t\teq(tables.tokens.tokenHash, tokenHash),\n\t\t\t\t\teq(tables.tokens.kind, kind),\n\t\t\t\t);\n\t\t\t\tconst [counted] = await db\n\t\t\t\t\t.update(tables.tokens)\n\t\t\t\t\t.set({ attempts: sql`${tables.tokens.attempts} + 1` })\n\t\t\t\t\t.where(and(match, isNull(tables.tokens.spentAt)))\n\t\t\t\t\t.returning();\n\t\t\t\tconst row =\n\t\t\t\t\tcounted ?? (await db.select().from(tables.tokens).where(match))[0];\n\t\t\t\treturn row === undefined ? null : { ...row, userId: row.userId as Id };\n\t\t\t}),\n\n\t\tspendUserTokens: (userId, kind, at, except) =>\n\t\t\trun$('spendUserTokens', async () => {\n\t\t\t\t// One statement: each row is written under its lock, and\n\t\t\t\t// re-checked after a concurrent `consumeToken` committed, so the\n\t\t\t\t// two never both spend it.\n\t\t\t\tconst spent = await db\n\t\t\t\t\t.update(tables.tokens)\n\t\t\t\t\t.set({ spentAt: at })\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(\n\t\t\t\t\t\t\teq(tables.tokens.userId, userId),\n\t\t\t\t\t\t\teq(tables.tokens.kind, kind),\n\t\t\t\t\t\t\tisNull(tables.tokens.spentAt),\n\t\t\t\t\t\t\texcept === undefined\n\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t: ne(tables.tokens.tokenHash, except),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\t.returning({ tokenHash: tables.tokens.tokenHash });\n\t\t\t\treturn spent.length;\n\t\t\t}),\n\n\t\tdeleteUserTokens: (userId) =>\n\t\t\trun$('deleteUserTokens', async () => {\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.tokens)\n\t\t\t\t\t.where(eq(tables.tokens.userId, userId))\n\t\t\t\t\t.returning({ tokenHash: tables.tokens.tokenHash });\n\t\t\t\treturn deleted.length;\n\t\t\t}),\n\t};\n}\n\n// ─── Rows and records ─────────────────────────────────────────────────────\n//\n// Each record is rebuilt field by field: the port's records are exactly what\n// it declares, and a row carries columns the record names differently.\n\nfunction toUserRow(record: UserRecord): UserInsert {\n\treturn {\n\t\tid: record.id,\n\t\ttype: record.type,\n\t\tschemaVersion: record.schemaVersion,\n\t\tactive: record.active,\n\t\tfields: record.fields,\n\t\tlogins: [...record.logins],\n\t\tpasswordHash: record.password?.hash ?? null,\n\t\tpasswordUpdatedAt: record.password?.updatedAt ?? null,\n\t\t...toSecondFactorColumns(record.secondFactor),\n\t\temailVerifiedAt: record.emailVerifiedAt,\n\t\tversion: record.version,\n\t\tcreatedAt: record.createdAt,\n\t\tupdatedAt: record.updatedAt,\n\t};\n}\n\n/**\n * The columns a patch names. A key present with `undefined` is absent, as the\n * port says — never an erasure. `password: null` is named, and removes the\n * password.\n */\nfunction toUserSet(patch: UserPatch): Partial<UserInsert> {\n\tconst set: Partial<UserInsert> = {\n\t\tupdatedAt: patch.updatedAt,\n\t};\n\tif (patch.schemaVersion !== undefined)\n\t\tset.schemaVersion = patch.schemaVersion;\n\tif (patch.active !== undefined) set.active = patch.active;\n\tif (patch.fields !== undefined) set.fields = patch.fields;\n\tif (patch.logins !== undefined) set.logins = [...patch.logins];\n\tif (patch.emailVerifiedAt !== undefined)\n\t\tset.emailVerifiedAt = patch.emailVerifiedAt;\n\tif (patch.password !== undefined) {\n\t\tset.passwordHash = patch.password?.hash ?? null;\n\t\tset.passwordUpdatedAt = patch.password?.updatedAt ?? null;\n\t}\n\tif (patch.secondFactor !== undefined) {\n\t\tObject.assign(set, toSecondFactorColumns(patch.secondFactor));\n\t}\n\treturn set;\n}\n\n/** A second factor as its four columns, all `null` for none. */\nfunction toSecondFactorColumns(secondFactor: UserRecord['secondFactor']) {\n\treturn {\n\t\tsecondFactorMethod: secondFactor?.method ?? null,\n\t\tsecondFactorSecret: secondFactor?.secret ?? null,\n\t\tsecondFactorConfirmedAt: secondFactor?.confirmedAt ?? null,\n\t\tsecondFactorLastStep: secondFactor?.lastStep ?? null,\n\t};\n}\n\nfunction toUser(row: UserRow): UserRecord {\n\treturn {\n\t\tid: row.id as Id,\n\t\ttype: row.type,\n\t\tschemaVersion: row.schemaVersion,\n\t\tactive: row.active,\n\t\tfields: row.fields as UserRecord['fields'],\n\t\tlogins: [...row.logins],\n\t\tpassword:\n\t\t\trow.passwordHash === null || row.passwordUpdatedAt === null\n\t\t\t\t? null\n\t\t\t\t: { hash: row.passwordHash, updatedAt: row.passwordUpdatedAt },\n\t\tsecondFactor:\n\t\t\trow.secondFactorMethod === null || row.secondFactorSecret === null\n\t\t\t\t? null\n\t\t\t\t: {\n\t\t\t\t\t\tmethod: row.secondFactorMethod,\n\t\t\t\t\t\tsecret: row.secondFactorSecret,\n\t\t\t\t\t\tconfirmedAt: row.secondFactorConfirmedAt,\n\t\t\t\t\t\tlastStep: row.secondFactorLastStep,\n\t\t\t\t\t},\n\t\temailVerifiedAt: row.emailVerifiedAt,\n\t\tversion: row.version,\n\t\tcreatedAt: row.createdAt,\n\t\tupdatedAt: row.updatedAt,\n\t};\n}\n\nfunction toSession(row: SessionRow): SessionRecord {\n\treturn {\n\t\tid: row.id,\n\t\ttokenHash: row.tokenHash,\n\t\tuserId: row.userId as Id,\n\t\tauthenticatedAt: row.authenticatedAt,\n\t\texpiresAt: row.expiresAt,\n\t\trevokedAt: row.revokedAt,\n\t\tcreatedAt: row.createdAt,\n\t};\n}\n\n/**\n * A `Date` inside a `sql` template, as every driver takes it: `timestamptz`\n * from its ISO string. Drizzle's column mapping does not reach a raw\n * template, and postgres.js refuses a `Date` object there.\n */\nfunction stamp(at: Date): SQL {\n\treturn sql`${at.toISOString()}::timestamptz`;\n}\n",
|
|
13
|
+
"import type {\n\tCursorPage,\n\tEntity,\n\tRelationTuple,\n\tSubjectSet,\n} from '@nxgt/janus';\nimport type { ObjectPageRequest } from '@nxgt/janus/permissions';\nimport { and, asc, eq, gt, isNotNull, isNull } from 'drizzle-orm';\nimport type { RelationContext } from './context';\nimport { matching, subjectIs } from './tuples';\n\nexport async function has(\n\t{ db, relations }: RelationContext,\n\ttuple: RelationTuple,\n): Promise<boolean> {\n\tconst found = await db\n\t\t.select({ relation: relations.relation })\n\t\t.from(relations)\n\t\t.where(matching(relations, tuple))\n\t\t.limit(1);\n\treturn found.length === 1;\n}\n\nexport async function findSubjectSets(\n\tcontext: RelationContext,\n\tobject: Entity,\n\trelation: string,\n): Promise<SubjectSet[]> {\n\treturn (await holding(context, object, relation, true)).map(\n\t\t(row): SubjectSet => ({\n\t\t\ttype: row.type,\n\t\t\tid: row.id,\n\t\t\trelation: row.relation ?? '',\n\t\t}),\n\t);\n}\n\nexport async function findEntities(\n\tcontext: RelationContext,\n\tobject: Entity,\n\trelation: string,\n): Promise<Entity[]> {\n\treturn (await holding(context, object, relation, false)).map(\n\t\t(row): Entity => ({ type: row.type, id: row.id }),\n\t);\n}\n\n/** One hop from an object: its subject sets, or its entities. */\nfunction holding(\n\t{ db, relations }: RelationContext,\n\tobject: Entity,\n\trelation: string,\n\tsets: boolean,\n) {\n\treturn db\n\t\t.select({\n\t\t\ttype: relations.subjectType,\n\t\t\tid: relations.subjectId,\n\t\t\trelation: relations.subjectRelation,\n\t\t})\n\t\t.from(relations)\n\t\t.where(\n\t\t\tand(\n\t\t\t\teq(relations.objectType, object.type),\n\t\t\t\teq(relations.objectId, object.id),\n\t\t\t\teq(relations.relation, relation),\n\t\t\t\tsets\n\t\t\t\t\t? isNotNull(relations.subjectRelation)\n\t\t\t\t\t: isNull(relations.subjectRelation),\n\t\t\t),\n\t\t);\n}\n\n/** A page of object ids, in id order, after the cursor. */\nexport async function findObjects(\n\t{ db, relations }: RelationContext,\n\t{ type, relation, subject, after, limit }: ObjectPageRequest,\n): Promise<CursorPage<string>> {\n\tconst conditions = [\n\t\tsubjectIs(relations, subject),\n\t\teq(relations.relation, relation),\n\t\teq(relations.objectType, type),\n\t];\n\tif (after !== null) conditions.push(gt(relations.objectId, after));\n\tconst found = await db\n\t\t.select({ id: relations.objectId })\n\t\t.from(relations)\n\t\t.where(and(...conditions))\n\t\t.orderBy(asc(relations.objectId))\n\t\t.limit(limit + 1);\n\tconst items = found.slice(0, limit).map((row) => row.id);\n\tconst last = items.at(-1);\n\treturn {\n\t\titems,\n\t\tnextCursor: found.length > limit && last !== undefined ? last : null,\n\t};\n}\n",
|
|
14
|
+
"import { isSubjectSet, type RelationTuple, type Subject } from '@nxgt/janus';\nimport { and, eq, isNull, type SQL } from 'drizzle-orm';\nimport type { Relations } from './context';\n\n/** Tuples in one order: their notation, compared by code unit. */\nexport function inOrder(\n\ttuples: readonly RelationTuple[],\n): readonly RelationTuple[] {\n\tconst keyOf = (tuple: RelationTuple) =>\n\t\tJSON.stringify([\n\t\t\ttuple.object.type,\n\t\t\ttuple.object.id,\n\t\t\ttuple.relation,\n\t\t\ttuple.subject.type,\n\t\t\ttuple.subject.id,\n\t\t\tisSubjectSet(tuple.subject) ? tuple.subject.relation : null,\n\t\t]);\n\treturn [...tuples].sort((a, b) => {\n\t\tconst [x, y] = [keyOf(a), keyOf(b)];\n\t\treturn x < y ? -1 : x > y ? 1 : 0;\n\t});\n}\n\n/** A tuple as a row: an entity's `subject_relation` is `null`. */\nexport function rowOf(tuple: RelationTuple): Relations['$inferInsert'] {\n\treturn {\n\t\tobjectType: tuple.object.type,\n\t\tobjectId: tuple.object.id,\n\t\trelation: tuple.relation,\n\t\tsubjectType: tuple.subject.type,\n\t\tsubjectId: tuple.subject.id,\n\t\tsubjectRelation: isSubjectSet(tuple.subject)\n\t\t\t? tuple.subject.relation\n\t\t\t: null,\n\t};\n}\n\n/** Exactly this subject: a subject set is not its entity, and the reverse. */\nexport function subjectIs(\n\trelations: Relations,\n\tsubject: Subject,\n): SQL | undefined {\n\treturn and(\n\t\teq(relations.subjectType, subject.type),\n\t\teq(relations.subjectId, subject.id),\n\t\tisSubjectSet(subject)\n\t\t\t? eq(relations.subjectRelation, subject.relation)\n\t\t\t: isNull(relations.subjectRelation),\n\t);\n}\n\n/** Exactly this tuple. */\nexport function matching(\n\trelations: Relations,\n\ttuple: RelationTuple,\n): SQL | undefined {\n\treturn and(\n\t\teq(relations.objectType, tuple.object.type),\n\t\teq(relations.objectId, tuple.object.id),\n\t\teq(relations.relation, tuple.relation),\n\t\tsubjectIs(relations, tuple.subject),\n\t);\n}\n",
|
|
15
|
+
"import { type PgDatabase, withTransaction } from '@nxgt/drizzle/pg';\nimport type { Entity, RelationTuple } from '@nxgt/janus';\nimport { and, eq, or } from 'drizzle-orm';\nimport type { RelationContext, Relations } from './context';\nimport { inOrder, matching, rowOf } from './tuples';\n\n/** One tuple in one statement; more in one transaction. */\nexport async function write(\n\t{ db, relations }: RelationContext,\n\tadd: readonly RelationTuple[],\n\tremove: readonly RelationTuple[],\n): Promise<void> {\n\tif (add.length + remove.length <= 1) return apply(db, relations, add, remove);\n\tawait withTransaction(db, (tx) => apply(tx, relations, add, remove));\n}\n\n/** Removals first, then additions. */\nasync function apply(\n\ttx: PgDatabase,\n\trelations: Relations,\n\tadd: readonly RelationTuple[],\n\tremove: readonly RelationTuple[],\n): Promise<void> {\n\t// In one order, so two writes touching the same tuples take their locks\n\t// alike and never deadlock.\n\tfor (const tuple of inOrder(remove)) {\n\t\tawait tx.delete(relations).where(matching(relations, tuple));\n\t}\n\tif (add.length > 0) {\n\t\t// A stored tuple meets the unique constraint, and is a no-op.\n\t\tawait tx\n\t\t\t.insert(relations)\n\t\t\t.values(inOrder(add).map(rowOf))\n\t\t\t.onConflictDoNothing();\n\t}\n}\n\n/** Every tuple naming the entity, as object or as subject. */\nexport async function deleteEntity(\n\t{ db, relations }: RelationContext,\n\tentity: Entity,\n): Promise<number> {\n\tconst deleted = await db\n\t\t.delete(relations)\n\t\t.where(\n\t\t\tor(\n\t\t\t\tand(\n\t\t\t\t\teq(relations.objectType, entity.type),\n\t\t\t\t\teq(relations.objectId, entity.id),\n\t\t\t\t),\n\t\t\t\tand(\n\t\t\t\t\teq(relations.subjectType, entity.type),\n\t\t\t\t\teq(relations.subjectId, entity.id),\n\t\t\t\t),\n\t\t\t),\n\t\t)\n\t\t.returning({ relation: relations.relation });\n\treturn deleted.length;\n}\n",
|
|
16
|
+
"import type { PgDatabase } from '@nxgt/drizzle/pg';\nimport type { RelationStore } from '@nxgt/janus/permissions';\nimport { type DrizzleAdapterOptions, defineJanusTables } from '../tables';\nimport { run } from '../translate';\nimport type { RelationContext } from './context';\nimport { findEntities, findObjects, findSubjectSets, has } from './reads';\nimport { deleteEntity, write } from './writes';\n\n/**\n * The relation store `permissions()` takes, over one PostgreSQL database\n * through Drizzle — and the one `janus({ relations })` deletes a user's\n * tuples from.\n *\n * ```ts\n * const access = permissions({ model, store: createDrizzleRelations(db) });\n * ```\n *\n * **A write of more than one tuple is a transaction**, `@nxgt/drizzle`'s\n * `withTransaction`: removals first, then additions, all or nothing. It is not\n * retried here — a write is idempotent, so the caller retries.\n */\nexport function createDrizzleRelations(\n\tdb: PgDatabase,\n\toptions: DrizzleAdapterOptions<'relations'> = {},\n): RelationStore {\n\tconst tables = options.tables ?? defineJanusTables();\n\tconst context: RelationContext = { db, relations: tables.relations };\n\tconst run$ = <T>(operation: string, body: () => Promise<T>) =>\n\t\trun('relations', operation, body);\n\n\treturn {\n\t\twrite: ({ add = [], remove = [] }) =>\n\t\t\trun$('write', () => write(context, add, remove)),\n\t\thas: (tuple) => run$('has', () => has(context, tuple)),\n\t\tfindSubjectSets: (object, relation) =>\n\t\t\trun$('findSubjectSets', () => findSubjectSets(context, object, relation)),\n\t\tfindEntities: (object, relation) =>\n\t\t\trun$('findEntities', () => findEntities(context, object, relation)),\n\t\t// The request is unpacked before `run$`, as `write`'s is and as it was\n\t\t// before the split, so a malformed request throws the caller's\n\t\t// TypeError at once instead of reading as an outage.\n\t\tfindObjects: ({ type, relation, subject, after, limit }) =>\n\t\t\trun$('findObjects', () =>\n\t\t\t\tfindObjects(context, { type, relation, subject, after, limit }),\n\t\t\t),\n\t\tdeleteEntity: (entity) =>\n\t\t\trun$('deleteEntity', () => deleteEntity(context, entity)),\n\t};\n}\n",
|
|
17
|
+
"import type { PgDatabase } from '@nxgt/drizzle/pg';\nimport type { SessionStore } from '@nxgt/janus';\nimport { and, eq, isNull, lte, ne, sql } from 'drizzle-orm';\nimport { run } from '../translate';\nimport type { IdentityTables } from './identity-tables';\nimport { stamp, toSession } from './records';\n\nexport function sessionStore(\n\tdb: PgDatabase,\n\ttables: IdentityTables,\n): SessionStore {\n\tconst run$ = <T>(operation: string, body: () => Promise<T>) =>\n\t\trun('sessions', operation, body);\n\n\treturn {\n\t\tinsertSession: (record) =>\n\t\t\trun$('insertSession', async () => {\n\t\t\t\t// Idempotent under retry: a session with this id is already there.\n\t\t\t\t// A collision on the token hash is not a retry, and fails.\n\t\t\t\tawait db\n\t\t\t\t\t.insert(tables.sessions)\n\t\t\t\t\t.values(record)\n\t\t\t\t\t.onConflictDoNothing({ target: tables.sessions.id });\n\t\t\t}),\n\n\t\tfindSessionByTokenHash: (tokenHash) =>\n\t\t\trun$('findSessionByTokenHash', async () => {\n\t\t\t\tconst [row] = await db\n\t\t\t\t\t.select()\n\t\t\t\t\t.from(tables.sessions)\n\t\t\t\t\t.where(eq(tables.sessions.tokenHash, tokenHash));\n\t\t\t\treturn row === undefined ? null : toSession(row);\n\t\t\t}),\n\n\t\textendSession: (id, expiresAt) =>\n\t\t\trun$('extendSession', async () => {\n\t\t\t\t// `revoked_at is null` in the condition: an extension racing a\n\t\t\t\t// revocation matches nothing, and never brings the session back.\n\t\t\t\tconst [row] = await db\n\t\t\t\t\t.update(tables.sessions)\n\t\t\t\t\t.set({ expiresAt })\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(eq(tables.sessions.id, id), isNull(tables.sessions.revokedAt)),\n\t\t\t\t\t)\n\t\t\t\t\t.returning();\n\t\t\t\treturn row === undefined ? null : toSession(row);\n\t\t\t}),\n\n\t\trevokeSession: (id, at) =>\n\t\t\trun$('revokeSession', () => revokeSession(db, tables, id, at)),\n\n\t\trevokeUserSessions: (userId, at, except) =>\n\t\t\trun$('revokeUserSessions', () =>\n\t\t\t\trevokeUserSessions(db, tables, userId, at, except),\n\t\t\t),\n\n\t\tdeleteUserSessions: (userId) =>\n\t\t\trun$('deleteUserSessions', async () => {\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.sessions)\n\t\t\t\t\t.where(eq(tables.sessions.userId, userId))\n\t\t\t\t\t.returning({ id: tables.sessions.id });\n\t\t\t\treturn deleted.length;\n\t\t\t}),\n\n\t\tdeleteExpiredSessions: (before) =>\n\t\t\trun$('deleteExpiredSessions', async () => {\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.sessions)\n\t\t\t\t\t.where(lte(tables.sessions.expiresAt, before))\n\t\t\t\t\t.returning({ id: tables.sessions.id });\n\t\t\t\treturn deleted.length;\n\t\t\t}),\n\t};\n}\n\nasync function revokeSession(\n\tdb: PgDatabase,\n\ttables: IdentityTables,\n\tid: string,\n\tat: Date,\n): Promise<boolean> {\n\t// `coalesce`, so a session already revoked keeps its first\n\t// `revokedAt` and still counts as matched.\n\tconst matched = await db\n\t\t.update(tables.sessions)\n\t\t.set({\n\t\t\trevokedAt: sql`coalesce(${tables.sessions.revokedAt}, ${stamp(at)})`,\n\t\t})\n\t\t.where(eq(tables.sessions.id, id))\n\t\t.returning({ id: tables.sessions.id });\n\treturn matched.length === 1;\n}\n\nasync function revokeUserSessions(\n\tdb: PgDatabase,\n\ttables: IdentityTables,\n\tuserId: string,\n\tat: Date,\n\texcept: string | undefined,\n): Promise<number> {\n\tconst standing = and(\n\t\teq(tables.sessions.userId, userId),\n\t\tisNull(tables.sessions.revokedAt),\n\t);\n\tconst revoked = await db\n\t\t.update(tables.sessions)\n\t\t.set({ revokedAt: at })\n\t\t.where(\n\t\t\texcept === undefined\n\t\t\t\t? standing\n\t\t\t\t: and(standing, ne(tables.sessions.id, except)),\n\t\t)\n\t\t.returning({ id: tables.sessions.id });\n\treturn revoked.length;\n}\n",
|
|
18
|
+
"import type { Id, SessionRecord, UserPatch, UserRecord } from '@nxgt/janus';\nimport { type SQL, sql } from 'drizzle-orm';\nimport type { JanusTables } from '../tables';\n\n// ─── Rows and records ─────────────────────────────────────────────────────\n//\n// Each record is rebuilt field by field: the port's records are exactly what\n// it declares, and a row carries columns the record names differently.\n\ntype UserRow = JanusTables['users']['$inferSelect'];\ntype UserInsert = JanusTables['users']['$inferInsert'];\ntype SessionRow = JanusTables['sessions']['$inferSelect'];\n\nexport function toUserRow(record: UserRecord): UserInsert {\n\treturn {\n\t\tid: record.id,\n\t\ttype: record.type,\n\t\tschemaVersion: record.schemaVersion,\n\t\tactive: record.active,\n\t\tfields: record.fields,\n\t\tlogins: [...record.logins],\n\t\tpasswordHash: record.password?.hash ?? null,\n\t\tpasswordUpdatedAt: record.password?.updatedAt ?? null,\n\t\t...toSecondFactorColumns(record.secondFactor),\n\t\temailVerifiedAt: record.emailVerifiedAt,\n\t\tversion: record.version,\n\t\tcreatedAt: record.createdAt,\n\t\tupdatedAt: record.updatedAt,\n\t};\n}\n\n/**\n * The columns a patch names. A key present with `undefined` is absent, as the\n * port says — never an erasure. `password: null` is named, and removes the\n * password.\n */\nexport function toUserSet(patch: UserPatch): Partial<UserInsert> {\n\tconst set: Partial<UserInsert> = {\n\t\tupdatedAt: patch.updatedAt,\n\t};\n\tif (patch.schemaVersion !== undefined)\n\t\tset.schemaVersion = patch.schemaVersion;\n\tif (patch.active !== undefined) set.active = patch.active;\n\tif (patch.fields !== undefined) set.fields = patch.fields;\n\tif (patch.logins !== undefined) set.logins = [...patch.logins];\n\tif (patch.emailVerifiedAt !== undefined)\n\t\tset.emailVerifiedAt = patch.emailVerifiedAt;\n\tif (patch.password !== undefined) {\n\t\tset.passwordHash = patch.password?.hash ?? null;\n\t\tset.passwordUpdatedAt = patch.password?.updatedAt ?? null;\n\t}\n\tif (patch.secondFactor !== undefined) {\n\t\tObject.assign(set, toSecondFactorColumns(patch.secondFactor));\n\t}\n\treturn set;\n}\n\n/** A second factor as its four columns, all `null` for none. */\nfunction toSecondFactorColumns(secondFactor: UserRecord['secondFactor']) {\n\treturn {\n\t\tsecondFactorMethod: secondFactor?.method ?? null,\n\t\tsecondFactorSecret: secondFactor?.secret ?? null,\n\t\tsecondFactorConfirmedAt: secondFactor?.confirmedAt ?? null,\n\t\tsecondFactorLastStep: secondFactor?.lastStep ?? null,\n\t};\n}\n\nexport function toUser(row: UserRow): UserRecord {\n\treturn {\n\t\tid: row.id as Id,\n\t\ttype: row.type,\n\t\tschemaVersion: row.schemaVersion,\n\t\tactive: row.active,\n\t\tfields: row.fields as UserRecord['fields'],\n\t\tlogins: [...row.logins],\n\t\tpassword:\n\t\t\trow.passwordHash === null || row.passwordUpdatedAt === null\n\t\t\t\t? null\n\t\t\t\t: { hash: row.passwordHash, updatedAt: row.passwordUpdatedAt },\n\t\tsecondFactor:\n\t\t\trow.secondFactorMethod === null || row.secondFactorSecret === null\n\t\t\t\t? null\n\t\t\t\t: {\n\t\t\t\t\t\tmethod: row.secondFactorMethod,\n\t\t\t\t\t\tsecret: row.secondFactorSecret,\n\t\t\t\t\t\tconfirmedAt: row.secondFactorConfirmedAt,\n\t\t\t\t\t\tlastStep: row.secondFactorLastStep,\n\t\t\t\t\t},\n\t\temailVerifiedAt: row.emailVerifiedAt,\n\t\tversion: row.version,\n\t\tcreatedAt: row.createdAt,\n\t\tupdatedAt: row.updatedAt,\n\t};\n}\n\nexport function toSession(row: SessionRow): SessionRecord {\n\treturn {\n\t\tid: row.id,\n\t\ttokenHash: row.tokenHash,\n\t\tuserId: row.userId as Id,\n\t\tauthenticatedAt: row.authenticatedAt,\n\t\texpiresAt: row.expiresAt,\n\t\trevokedAt: row.revokedAt,\n\t\tcreatedAt: row.createdAt,\n\t};\n}\n\n/**\n * A `Date` inside a `sql` template, as every driver takes it: `timestamptz`\n * from its ISO string. Drizzle's column mapping does not reach a raw\n * template, and postgres.js refuses a `Date` object there.\n */\nexport function stamp(at: Date): SQL {\n\treturn sql`${at.toISOString()}::timestamptz`;\n}\n",
|
|
19
|
+
"import type { PgDatabase } from '@nxgt/drizzle/pg';\nimport type { Id, TokenKind, TokenRecord, TokenStore } from '@nxgt/janus';\nimport { and, eq, isNull, ne, sql } from 'drizzle-orm';\nimport { run } from '../translate';\nimport type { IdentityTables } from './identity-tables';\nimport { stamp } from './records';\n\nexport function tokenStore(db: PgDatabase, tables: IdentityTables): TokenStore {\n\tconst run$ = <T>(operation: string, body: () => Promise<T>) =>\n\t\trun('tokens', operation, body);\n\n\treturn {\n\t\tinsertToken: (record) =>\n\t\t\trun$('insertToken', async () => {\n\t\t\t\t// The hash is the key: a collision is a retry.\n\t\t\t\tawait db.insert(tables.tokens).values(record).onConflictDoNothing();\n\t\t\t}),\n\n\t\tconsumeToken: (tokenHash, kind, at) =>\n\t\t\trun$('consumeToken', () => consumeToken(db, tables, tokenHash, kind, at)),\n\n\t\tcountAttempt: (tokenHash, kind) =>\n\t\t\trun$('countAttempt', () => countAttempt(db, tables, tokenHash, kind)),\n\n\t\tspendUserTokens: (userId, kind, at, except) =>\n\t\t\trun$('spendUserTokens', async () => {\n\t\t\t\t// One statement: each row is written under its lock, and\n\t\t\t\t// re-checked after a concurrent `consumeToken` committed, so the\n\t\t\t\t// two never both spend it.\n\t\t\t\tconst spent = await db\n\t\t\t\t\t.update(tables.tokens)\n\t\t\t\t\t.set({ spentAt: at })\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(\n\t\t\t\t\t\t\teq(tables.tokens.userId, userId),\n\t\t\t\t\t\t\teq(tables.tokens.kind, kind),\n\t\t\t\t\t\t\tisNull(tables.tokens.spentAt),\n\t\t\t\t\t\t\texcept === undefined\n\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t: ne(tables.tokens.tokenHash, except),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\t.returning({ tokenHash: tables.tokens.tokenHash });\n\t\t\t\treturn spent.length;\n\t\t\t}),\n\n\t\tdeleteUserTokens: (userId) =>\n\t\t\trun$('deleteUserTokens', async () => {\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.tokens)\n\t\t\t\t\t.where(eq(tables.tokens.userId, userId))\n\t\t\t\t\t.returning({ tokenHash: tables.tokens.tokenHash });\n\t\t\t\treturn deleted.length;\n\t\t\t}),\n\t};\n}\n\nasync function consumeToken(\n\tdb: PgDatabase,\n\ttables: IdentityTables,\n\ttokenHash: string,\n\tkind: TokenKind,\n\tat: Date,\n): Promise<TokenRecord | null> {\n\t// **One conditional write**, answering the row as it was before\n\t// it. `for update` makes a concurrent call wait for this one and\n\t// then read the spent row, so exactly one caller ever reads\n\t// `spentAt: null`; `coalesce` keeps a first `spentAt`.\n\tconst before = db.$with('before').as(\n\t\tdb\n\t\t\t.select()\n\t\t\t.from(tables.tokens)\n\t\t\t.where(\n\t\t\t\tand(\n\t\t\t\t\teq(tables.tokens.tokenHash, tokenHash),\n\t\t\t\t\teq(tables.tokens.kind, kind),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.for('update'),\n\t);\n\tconst [spent] = await db\n\t\t.with(before)\n\t\t.update(tables.tokens)\n\t\t.set({\n\t\t\tspentAt: sql`coalesce(${tables.tokens.spentAt}, ${stamp(at)})`,\n\t\t})\n\t\t.from(before)\n\t\t.where(eq(tables.tokens.tokenHash, before.tokenHash))\n\t\t.returning({\n\t\t\ttokenHash: before.tokenHash,\n\t\t\tkind: before.kind,\n\t\t\tuserId: before.userId,\n\t\t\taddress: before.address,\n\t\t\tcodeHash: before.codeHash,\n\t\t\tattempts: before.attempts,\n\t\t\texpiresAt: before.expiresAt,\n\t\t\tspentAt: before.spentAt,\n\t\t\tcreatedAt: before.createdAt,\n\t\t});\n\treturn spent === undefined ? null : { ...spent, userId: spent.userId as Id };\n}\n\nasync function countAttempt(\n\tdb: PgDatabase,\n\ttables: IdentityTables,\n\ttokenHash: string,\n\tkind: TokenKind,\n): Promise<TokenRecord | null> {\n\t// **One conditional write**: `attempts + 1` on the row, under the\n\t// row's lock, so twenty concurrent calls answer twenty counts. A\n\t// spent token matches nothing here, and is read as it is below.\n\tconst match = and(\n\t\teq(tables.tokens.tokenHash, tokenHash),\n\t\teq(tables.tokens.kind, kind),\n\t);\n\tconst [counted] = await db\n\t\t.update(tables.tokens)\n\t\t.set({ attempts: sql`${tables.tokens.attempts} + 1` })\n\t\t.where(and(match, isNull(tables.tokens.spentAt)))\n\t\t.returning();\n\tconst row =\n\t\tcounted ?? (await db.select().from(tables.tokens).where(match))[0];\n\treturn row === undefined ? null : { ...row, userId: row.userId as Id };\n}\n",
|
|
20
|
+
"import { type PgDatabase, withTransaction } from '@nxgt/drizzle/pg';\nimport type { UserPatch, UserRecord, UserStore } from '@nxgt/janus';\nimport { NotFoundError, StoreConflict } from '@nxgt/janus';\nimport { and, asc, eq, gt, sql } from 'drizzle-orm';\nimport { run } from '../translate';\nimport type { IdentityTables } from './identity-tables';\nimport { claimLogins } from './logins';\nimport { toUser, toUserRow, toUserSet } from './records';\n\nexport function userStore(db: PgDatabase, tables: IdentityTables): UserStore {\n\tconst run$ = <T>(operation: string, body: () => Promise<T>) =>\n\t\trun('users', operation, body);\n\n\treturn {\n\t\tinsertUser: (record) =>\n\t\t\trun$('insertUser', () => insertUser(db, tables, record)),\n\n\t\tfindUser: (id) => run$('findUser', () => findUser(db, tables, id)),\n\n\t\tfindUserByLogin: (type, login) =>\n\t\t\trun$('findUserByLogin', async () => {\n\t\t\t\tconst [row] = await db\n\t\t\t\t\t.select({ user: tables.users })\n\t\t\t\t\t.from(tables.logins)\n\t\t\t\t\t.innerJoin(tables.users, eq(tables.users.id, tables.logins.userId))\n\t\t\t\t\t.where(\n\t\t\t\t\t\tand(eq(tables.logins.type, type), eq(tables.logins.login, login)),\n\t\t\t\t\t);\n\t\t\t\treturn row === undefined ? null : toUser(row.user);\n\t\t\t}),\n\n\t\tlistUsers: ({ type, after, limit }) =>\n\t\t\trun$('listUsers', async () => {\n\t\t\t\t// One more than the page, to know whether another follows.\n\t\t\t\tconst found = await db\n\t\t\t\t\t.select()\n\t\t\t\t\t.from(tables.users)\n\t\t\t\t\t.where(\n\t\t\t\t\t\tafter === null\n\t\t\t\t\t\t\t? eq(tables.users.type, type)\n\t\t\t\t\t\t\t: and(eq(tables.users.type, type), gt(tables.users.id, after)),\n\t\t\t\t\t)\n\t\t\t\t\t.orderBy(asc(tables.users.id))\n\t\t\t\t\t.limit(limit + 1);\n\t\t\t\tconst items = found.slice(0, limit).map(toUser);\n\t\t\t\tconst last = items.at(-1);\n\t\t\t\treturn {\n\t\t\t\t\titems,\n\t\t\t\t\tnextCursor:\n\t\t\t\t\t\tfound.length > limit && last !== undefined ? last.id : null,\n\t\t\t\t};\n\t\t\t}),\n\n\t\tupdateUser: (id, patch, ifVersion) =>\n\t\t\trun$('updateUser', () =>\n\t\t\t\twithTransaction(db, (tx) =>\n\t\t\t\t\tupdateUser(tx, tables, id, patch, ifVersion),\n\t\t\t\t),\n\t\t\t),\n\n\t\tdeleteUser: (id) =>\n\t\t\trun$('deleteUser', async () => {\n\t\t\t\t// The logins go with it: their foreign key cascades.\n\t\t\t\tconst deleted = await db\n\t\t\t\t\t.delete(tables.users)\n\t\t\t\t\t.where(eq(tables.users.id, id))\n\t\t\t\t\t.returning({ id: tables.users.id });\n\t\t\t\treturn deleted.length === 1;\n\t\t\t}),\n\t};\n}\n\nasync function findUser(\n\tdb: PgDatabase,\n\ttables: IdentityTables,\n\tid: string,\n): Promise<UserRecord | null> {\n\tconst [row] = await db\n\t\t.select()\n\t\t.from(tables.users)\n\t\t.where(eq(tables.users.id, id));\n\treturn row === undefined ? null : toUser(row);\n}\n\nasync function insertUser(\n\tdb: PgDatabase,\n\ttables: IdentityTables,\n\trecord: UserRecord,\n): Promise<UserRecord> {\n\tconst inserted = await withTransaction(db, async (tx) => {\n\t\tconst [row] = await tx\n\t\t\t.insert(tables.users)\n\t\t\t.values(toUserRow(record))\n\t\t\t.onConflictDoNothing({ target: tables.users.id })\n\t\t\t.returning();\n\t\tif (row === undefined) return null;\n\t\tawait claimLogins(tx, tables, 'insertUser', record, record.logins);\n\t\treturn toUser(row);\n\t});\n\tif (inserted !== null) return inserted;\n\n\t// A retry whose first attempt landed: the user with this id is\n\t// there, and is the answer — logins included, which are theirs.\n\tconst stored = await findUser(db, tables, record.id);\n\tif (stored !== null) return stored;\n\t// Deleted between the two statements: a retry of nothing.\n\tthrow new NotFoundError('insertUser: the user was deleted meanwhile', {\n\t\tuserId: record.id,\n\t\toperation: 'insertUser',\n\t});\n}\n\nasync function updateUser(\n\ttx: PgDatabase,\n\ttables: IdentityTables,\n\tid: string,\n\tpatch: UserPatch,\n\tifVersion: number,\n): Promise<UserRecord> {\n\tconst [row] = await tx\n\t\t.update(tables.users)\n\t\t.set({\n\t\t\t...toUserSet(patch),\n\t\t\tversion: sql`${tables.users.version} + 1`,\n\t\t})\n\t\t.where(and(eq(tables.users.id, id), eq(tables.users.version, ifVersion)))\n\t\t.returning();\n\n\tif (row === undefined) {\n\t\t// The write matched nothing, which alone cannot tell an unknown\n\t\t// id from a moved version: read again, and say which.\n\t\tconst [stored] = await tx\n\t\t\t.select({ version: tables.users.version })\n\t\t\t.from(tables.users)\n\t\t\t.where(eq(tables.users.id, id));\n\t\tif (stored === undefined) {\n\t\t\tthrow new NotFoundError('updateUser: no user has this id', {\n\t\t\t\tuserId: id,\n\t\t\t\toperation: 'updateUser',\n\t\t\t});\n\t\t}\n\t\tthrow new StoreConflict(\n\t\t\t'version',\n\t\t\t`updateUser: expected version ${ifVersion}, found ${stored.version}`,\n\t\t\t{\n\t\t\t\tuserId: id,\n\t\t\t\texpectedVersion: ifVersion,\n\t\t\t\tactualVersion: stored.version,\n\t\t\t\toperation: 'updateUser',\n\t\t\t},\n\t\t);\n\t}\n\n\tif (patch.logins !== undefined) {\n\t\tawait tx.delete(tables.logins).where(eq(tables.logins.userId, id));\n\t\tawait claimLogins(tx, tables, 'updateUser', row, patch.logins);\n\t}\n\treturn toUser(row);\n}\n",
|
|
21
|
+
"import type { PgDatabase } from '@nxgt/drizzle/pg';\nimport { loginTaken } from '../translate';\nimport type { IdentityTables } from './identity-tables';\n\n/**\n * Writes the logins of one user, and throws the port's conflict for the\n * first one another user of the type holds. `on conflict do nothing`: a\n * login the statement did not write is one somebody else holds, and a\n * concurrent sign-up waits for the first to commit, then writes nothing.\n */\nexport async function claimLogins(\n\ttx: PgDatabase,\n\ttables: IdentityTables,\n\toperation: string,\n\tuser: { readonly id: string; readonly type: string },\n\tlogins: readonly string[],\n): Promise<void> {\n\t// Sorted: two transactions claiming the same logins take their locks in\n\t// one order, and never deadlock — the loser waits, then finds them taken.\n\tconst distinct = [...new Set(logins)].sort();\n\tif (distinct.length === 0) return;\n\tconst written = await tx\n\t\t.insert(tables.logins)\n\t\t.values(\n\t\t\tdistinct.map((login) => ({ type: user.type, login, userId: user.id })),\n\t\t)\n\t\t.onConflictDoNothing()\n\t\t.returning({ login: tables.logins.login });\n\tif (written.length === distinct.length) return;\n\tconst claimed = new Set(written.map((row) => row.login));\n\tconst taken = distinct.find((login) => !claimed.has(login)) ?? '';\n\tthrow loginTaken(operation, user.type, taken);\n}\n",
|
|
22
|
+
"import type { PgDatabase } from '@nxgt/drizzle/pg';\nimport type { JanusStores } from '@nxgt/janus';\nimport { type DrizzleAdapterOptions, defineJanusTables } from '../tables';\nimport type { IdentityTable } from './identity-tables';\nimport { sessionStore } from './sessions';\nimport { tokenStore } from './tokens';\nimport { userStore } from './users';\n\n/**\n * The three stores `janus()` takes, over one PostgreSQL database through\n * Drizzle.\n *\n * ```ts\n * const db = drizzle(process.env.DATABASE_URL);\n * const auth = janus({ user, password: { login: 'email' }, store: createDrizzleStores(db), hasher });\n * ```\n *\n * **Every read is one statement**, whose absence is an empty result, turned\n * into `null` here; everything that arrives as a rejection is a failure. There\n * is no path on which an absence and an outage travel the same channel.\n *\n * **A user is written in one transaction** with its logins, whose table holds\n * their uniqueness — `@nxgt/drizzle`'s `withTransaction`, inside the method,\n * as rule 5 allows. Every other write is one statement.\n *\n * `sessions.deleteExpiredSessions` is implemented: PostgreSQL has no TTL, so\n * `auth.collectExpired()` is how lapsed sessions leave the table.\n *\n * `{ tables }` is what your schema file exports; absent, the tables in the\n * connection's `search_path`.\n */\nexport function createDrizzleStores(\n\tdb: PgDatabase,\n\toptions: DrizzleAdapterOptions<IdentityTable> = {},\n): JanusStores {\n\tconst tables = options.tables ?? defineJanusTables();\n\treturn {\n\t\tusers: userStore(db, tables),\n\t\tsessions: sessionStore(db, tables),\n\t\ttokens: tokenStore(db, tables),\n\t};\n}\n",
|
|
9
23
|
"import type { PgDatabase } from '@nxgt/drizzle/pg';\nimport type { JanusStores } from '@nxgt/janus';\nimport type { RelationStore } from '@nxgt/janus/permissions';\nimport { createDrizzleRelations } from './relations';\nimport { createDrizzleStores } from './stores';\nimport type { DrizzleAdapterOptions } from './tables';\n\n/** The whole adapter over one database, keyed as `janus()` takes it. */\nexport interface DrizzleAdapter {\n\t/** The identity stores: `createDrizzleStores(db)`. */\n\treadonly store: JanusStores;\n\t/** The relation store: `createDrizzleRelations(db)`. */\n\treadonly relations: RelationStore;\n}\n\n/**\n * The identity stores and the relation store over one database, under the\n * names `janus()` takes them — so one spread wires both, and deleting a user\n * deletes every tuple naming them:\n *\n * ```ts\n * const postgres = createDrizzleAdapter(db);\n * const auth = janus({ user, password: { login: 'email' }, hasher, ...postgres });\n * const access = permissions({ model, store: postgres.relations });\n * ```\n *\n * It connects to nothing and creates nothing: `db` is your Drizzle instance,\n * and the tables are your migrations'. `{ tables }` is what your schema file\n * exports, needed when they are in a PostgreSQL schema of their own. An\n * application that only authenticates can take `createDrizzleStores(db)` alone.\n */\nexport function createDrizzleAdapter(\n\tdb: PgDatabase,\n\toptions: DrizzleAdapterOptions = {},\n): DrizzleAdapter {\n\treturn {\n\t\tstore: createDrizzleStores(db, options),\n\t\trelations: createDrizzleRelations(db, options),\n\t};\n}\n"
|
|
10
24
|
],
|
|
11
|
-
"mappings": ";AAAA;AACA;AAAA;AAAA;AAQA;;;ACTA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDA,IAAM,MAAM,WAAiD;AAAA,EAC5D,UAAU,MAAM;AACjB,CAAC;AAKD,IAAM,KAAK,CAAC,SACX,UAAU,MAAM,EAAE,cAAc,MAAM,WAAW,EAAE,CAAC;AAiB9C,SAAS,iBAAiB,CAAC,UAA8B,CAAC,GAAG;AAAA,EACnE,QAAQ,WAAW;AAAA,EACnB,MAAM,QACL,WAAW,YAAY,UAAU,OAAO;AAAA,EAOzC,MAAM,QAAQ,MACb,SACA;AAAA,IAEC,IAAI,IAAI,IAAI,EAAE,WAAW;AAAA,IACzB,MAAM,IAAI,MAAM,EAAE,QAAQ;AAAA,IAC1B,eAAe,KAAK,gBAAgB,EAAE,QAAQ;AAAA,IAC9C,QAAQ,QAAQ,QAAQ,EAAE,QAAQ;AAAA,IAElC,QAAQ,MAAM,QAAQ,EAAE,QAAQ;AAAA,IAChC,QAAQ,KAAK,QAAQ,EAAE,MAAM,EAAE,QAAQ;AAAA,IACvC,cAAc,KAAK,eAAe;AAAA,IAClC,mBAAmB,GAAG,qBAAqB;AAAA,IAE3C,oBAAoB,KAAK,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AAAA,IAEnE,oBAAoB,KAAK,sBAAsB;AAAA,IAC/C,yBAAyB,GAAG,4BAA4B;AAAA,IACxD,sBAAsB,QAAQ,yBAAyB;AAAA,IACvD,iBAAiB,GAAG,mBAAmB;AAAA,IACvC,SAAS,QAAQ,SAAS,EAAE,QAAQ;AAAA,IACpC,WAAW,GAAG,YAAY,EAAE,QAAQ;AAAA,IACpC,WAAW,GAAG,YAAY,EAAE,QAAQ;AAAA,EACrC,GACA,CAAC,MAAM;AAAA,IAEN,OAAO,sBAAsB,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI;AAAA,IAE9C,MAAM,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;AAAA,IAEtC,MACC,wBACA,OAAO,EAAE,4BAA4B,EAAE,4BACxC;AAAA,IAKA,MACC,6BACA,OAAO,EAAE,kCAAkC,EAAE,oCAAoC,EAAE,sCAAsC,EAAE,uCAAuC,EAAE,gCACrK;AAAA,IAEA,MACC,8BACA,MAAM,EAAE,sCAAsC,EAAE,2BACjD;AAAA,EACD,CACD;AAAA,EASA,MAAM,SAAS,MACd,UACA;AAAA,IACC,MAAM,IAAI,MAAM,EAAE,QAAQ;AAAA,IAC1B,OAAO,IAAI,OAAO,EAAE,QAAQ;AAAA,IAC5B,QAAQ,IAAI,SAAS,EAAE,QAAQ;AAAA,EAChC,GACA,CAAC,MAAM;AAAA,IACN,WAAW,EAAE,MAAM,eAAe,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAAA,IAC9D,WAAW;AAAA,MACV,MAAM;AAAA,MACN,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI;AAAA,MAC1B,gBAAgB,CAAC,MAAM,IAAI,MAAM,IAAI;AAAA,IACtC,CAAC,EAAE,SAAS,SAAS;AAAA,IACrB,MAAM,gBAAgB,EAAE,GAAG,EAAE,MAAM;AAAA,EACpC,CACD;AAAA,EAOA,MAAM,WAAW,MAChB,YACA;AAAA,IACC,IAAI,IAAI,IAAI,EAAE,WAAW;AAAA,IAEzB,WAAW,IAAI,YAAY,EAAE,QAAQ;AAAA,IACrC,QAAQ,IAAI,SAAS,EAAE,QAAQ;AAAA,IAC/B,iBAAiB,GAAG,kBAAkB,EAAE,QAAQ;AAAA,IAChD,WAAW,GAAG,YAAY,EAAE,QAAQ;AAAA,IACpC,WAAW,GAAG,YAAY;AAAA,IAC1B,WAAW,GAAG,YAAY,EAAE,QAAQ;AAAA,EACrC,GACA,CAAC,MAAM;AAAA,IACN,OAAO,4BAA4B,EAAE,GAAG,EAAE,SAAS;AAAA,IACnD,MAAM,kBAAkB,EAAE,GAAG,EAAE,MAAM;AAAA,IAErC,MAAM,qBAAqB,EAAE,GAAG,EAAE,SAAS;AAAA,EAC5C,CACD;AAAA,EAGA,MAAM,SAAS,MACd,UACA;AAAA,IACC,WAAW,IAAI,YAAY,EAAE,WAAW;AAAA,IACxC,MAAM,KAAK,QAAQ;AAAA,MAClB,MAAM,CAAC,eAAe,iBAAiB,gBAAgB,YAAY;AAAA,IACpE,CAAC,EAAE,QAAQ;AAAA,IACX,QAAQ,IAAI,SAAS,EAAE,QAAQ;AAAA,IAC/B,SAAS,KAAK,SAAS,EAAE,QAAQ;AAAA,IAEjC,UAAU,KAAK,WAAW;AAAA,IAE1B,UAAU,QAAQ,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,IACjD,WAAW,GAAG,YAAY,EAAE,QAAQ;AAAA,IACpC,SAAS,GAAG,UAAU;AAAA,IACtB,WAAW,GAAG,YAAY,EAAE,QAAQ;AAAA,EACrC,GACA,CAAC,MAAM;AAAA,IACN,MACC,eACA,MAAM,EAAE,wEACT;AAAA,IACA,MAAM,mBAAmB,MAAM,EAAE,eAAe;AAAA,IAChD,MAAM,gBAAgB,EAAE,GAAG,EAAE,MAAM;AAAA,EACpC,CACD;AAAA,EAYA,MAAM,YAAY,MACjB,aACA;AAAA,IACC,YAAY,IAAI,aAAa,EAAE,QAAQ;AAAA,IACvC,UAAU,IAAI,WAAW,EAAE,QAAQ;AAAA,IACnC,UAAU,IAAI,UAAU,EAAE,QAAQ;AAAA,IAClC,aAAa,IAAI,cAAc,EAAE,QAAQ;AAAA,IACzC,WAAW,IAAI,YAAY,EAAE,QAAQ;AAAA,IACrC,iBAAiB,IAAI,kBAAkB;AAAA,EACxC,GACA,CAAC,MAAM;AAAA,IACN,OAAO,wBAAwB,EAC7B,GACA,EAAE,aACF,EAAE,WACF,EAAE,iBACF,EAAE,UACF,EAAE,YACF,EAAE,QACH,EACC,iBAAiB;AAAA,IAEnB,MAAM,kBAAkB,EAAE,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ;AAAA,EAClE,CACD;AAAA,EAEA,OAAO,EAAE,OAAO,QAAQ,UAAU,QAAQ,UAAU;AAAA;;;AC9PrD;AACA;AA8BA,eAAsB,GAAM,CAC3B,MACA,WACA,MACa;AAAA,EACb,IAAI;AAAA,IACH,OAAO,MAAM,KAAK;AAAA,IACjB,OAAO,OAAO;AAAA,IAEf,IAAI,iBAAiB;AAAA,MAAY,MAAM;AAAA,IACvC,MAAM,IAAI,aAAa,GAAG,QAAQ,yCAAyC;AAAA,MAC1E;AAAA,MACA;AAAA,MACA,OAAO,YAAY,KAAK;AAAA,IACzB,CAAC;AAAA;AAAA;AAKI,SAAS,UAAU,CACzB,WACA,MACA,OACgB;AAAA,EAChB,OAAO,IAAI,cACV,SACA,GAAG,4CAA4C,QAC/C,EAAE,OAAO,UAAU,MAAM,UAAU,CACpC;AAAA;;;AF7BM,SAAS,sBAAsB,CACrC,IACA,UAA8C,CAAC,GAC/B;AAAA,EAChB,MAAM,SAAS,QAAQ,UAAU,kBAAkB;AAAA,EACnD,QAAQ,OAAO,WAAW,aAAa,SAAS,OAAO,SAAS;AAAA,EAChE,MAAM,OAAO,CAAI,WAAmB,SACnC,IAAI,aAAa,WAAW,IAAI;AAAA,EAGjC,MAAM,UAAU,CAAC,QAAgB,UAAkB,SAClD,GACE,OAAO;AAAA,IACP,MAAM,OAAO,UAAU;AAAA,IACvB,IAAI,OAAO,UAAU;AAAA,IACrB,UAAU,OAAO,UAAU;AAAA,EAC5B,CAAC,EACA,KAAK,OAAO,SAAS,EACrB,MACA,IACC,GAAG,OAAO,UAAU,YAAY,OAAO,IAAI,GAC3C,GAAG,OAAO,UAAU,UAAU,OAAO,EAAE,GACvC,GAAG,OAAO,UAAU,UAAU,QAAQ,GACtC,OACG,UAAU,OAAO,UAAU,eAAe,IAC1C,OAAO,OAAO,UAAU,eAAe,CAC3C,CACD;AAAA,EAEF,MAAM,QAAQ,OACb,IACA,KACA,WACI;AAAA,IAGJ,WAAW,SAAS,QAAQ,MAAM,GAAG;AAAA,MACpC,MAAM,GAAG,OAAO,OAAO,SAAS,EAAE,MAAM,SAAS,KAAK,CAAC;AAAA,IACxD;AAAA,IACA,IAAI,IAAI,SAAS,GAAG;AAAA,MAEnB,MAAM,GACJ,OAAO,OAAO,SAAS,EACvB,OAAO,QAAQ,GAAG,EAAE,IAAI,KAAK,CAAC,EAC9B,oBAAoB;AAAA,IACvB;AAAA;AAAA,EAGD,OAAO;AAAA,IACN,OAAO,GAAG,MAAM,CAAC,GAAG,SAAS,CAAC,QAC7B,KAAK,SAAS,YAAY;AAAA,MACzB,IAAI,IAAI,SAAS,OAAO,UAAU;AAAA,QAAG,OAAO,MAAM,IAAI,KAAK,MAAM;AAAA,MACjE,MAAM,gBAAgB,IAAI,CAAC,OAAO,MAAM,IAAI,KAAK,MAAM,CAAC;AAAA,KACxD;AAAA,IAEF,KAAK,CAAC,UACL,KAAK,OAAO,YAAY;AAAA,MACvB,MAAM,QAAQ,MAAM,GAClB,OAAO,EAAE,UAAU,OAAO,UAAU,SAAS,CAAC,EAC9C,KAAK,OAAO,SAAS,EACrB,MAAM,SAAS,KAAK,CAAC,EACrB,MAAM,CAAC;AAAA,MACT,OAAO,MAAM,WAAW;AAAA,KACxB;AAAA,IAEF,iBAAiB,CAAC,QAAQ,aACzB,KAAK,mBAAmB,aACtB,MAAM,QAAQ,QAAQ,UAAU,IAAI,GAAG,IACvC,CAAC,SAAqB;AAAA,MACrB,MAAM,IAAI;AAAA,MACV,IAAI,IAAI;AAAA,MACR,UAAU,IAAI,YAAY;AAAA,IAC3B,EACD,CACD;AAAA,IAED,cAAc,CAAC,QAAQ,aACtB,KAAK,gBAAgB,aACnB,MAAM,QAAQ,QAAQ,UAAU,KAAK,GAAG,IACxC,CAAC,SAAiB,EAAE,MAAM,IAAI,MAAM,IAAI,IAAI,GAAG,EAChD,CACD;AAAA,IAED,aAAa,GAAG,MAAM,UAAU,SAAS,OAAO,YAC/C,KAAK,eAAe,YAAY;AAAA,MAC/B,MAAM,aAAa;AAAA,QAClB,UAAU,OAAO;AAAA,QACjB,GAAG,OAAO,UAAU,UAAU,QAAQ;AAAA,QACtC,GAAG,OAAO,UAAU,YAAY,IAAI;AAAA,MACrC;AAAA,MACA,IAAI,UAAU;AAAA,QACb,WAAW,KAAK,GAAG,OAAO,UAAU,UAAU,KAAK,CAAC;AAAA,MACrD,MAAM,QAAQ,MAAM,GAClB,OAAO,EAAE,IAAI,OAAO,UAAU,SAAS,CAAC,EACxC,KAAK,OAAO,SAAS,EACrB,MAAM,IAAI,GAAG,UAAU,CAAC,EACxB,QAAQ,IAAI,OAAO,UAAU,QAAQ,CAAC,EACtC,MAAM,QAAQ,CAAC;AAAA,MACjB,MAAM,QAAQ,MAAM,MAAM,GAAG,KAAK,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;AAAA,MACvD,MAAM,OAAO,MAAM,GAAG,EAAE;AAAA,MACxB,OAAO;AAAA,QACN;AAAA,QACA,YAAY,MAAM,SAAS,SAAS,SAAS,YAAY,OAAO;AAAA,MACjE;AAAA,KACA;AAAA,IAEF,cAAc,CAAC,WACd,KAAK,gBAAgB,YAAY;AAAA,MAChC,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,SAAS,EACvB,MACA,GACC,IACC,GAAG,OAAO,UAAU,YAAY,OAAO,IAAI,GAC3C,GAAG,OAAO,UAAU,UAAU,OAAO,EAAE,CACxC,GACA,IACC,GAAG,OAAO,UAAU,aAAa,OAAO,IAAI,GAC5C,GAAG,OAAO,UAAU,WAAW,OAAO,EAAE,CACzC,CACD,CACD,EACC,UAAU,EAAE,UAAU,OAAO,UAAU,SAAS,CAAC;AAAA,MACnD,OAAO,QAAQ;AAAA,KACf;AAAA,EACH;AAAA;AAID,SAAS,OAAO,CAAC,QAA4D;AAAA,EAC5E,MAAM,QAAQ,CAAC,UACd,KAAK,UAAU;AAAA,IACd,MAAM,OAAO;AAAA,IACb,MAAM,OAAO;AAAA,IACb,MAAM;AAAA,IACN,MAAM,QAAQ;AAAA,IACd,MAAM,QAAQ;AAAA,IACd,aAAa,MAAM,OAAO,IAAI,MAAM,QAAQ,WAAW;AAAA,EACxD,CAAC;AAAA,EACF,OAAO,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;AAAA,IACjC,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAAA,IAClC,OAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;AAAA,GAChC;AAAA;AAMF,SAAS,QAAQ,CAAC,WAAsB;AAAA,EAEvC,SAAS,KAAK,CAAC,OAAiD;AAAA,IAC/D,OAAO;AAAA,MACN,YAAY,MAAM,OAAO;AAAA,MACzB,UAAU,MAAM,OAAO;AAAA,MACvB,UAAU,MAAM;AAAA,MAChB,aAAa,MAAM,QAAQ;AAAA,MAC3B,WAAW,MAAM,QAAQ;AAAA,MACzB,iBAAiB,aAAa,MAAM,OAAO,IACxC,MAAM,QAAQ,WACd;AAAA,IACJ;AAAA;AAAA,EAID,SAAS,SAAS,CAAC,SAAmC;AAAA,IACrD,OAAO,IACN,GAAG,UAAU,aAAa,QAAQ,IAAI,GACtC,GAAG,UAAU,WAAW,QAAQ,EAAE,GAClC,aAAa,OAAO,IACjB,GAAG,UAAU,iBAAiB,QAAQ,QAAQ,IAC9C,OAAO,UAAU,eAAe,CACpC;AAAA;AAAA,EAID,SAAS,QAAQ,CAAC,OAAuC;AAAA,IACxD,OAAO,IACN,GAAG,UAAU,YAAY,MAAM,OAAO,IAAI,GAC1C,GAAG,UAAU,UAAU,MAAM,OAAO,EAAE,GACtC,GAAG,UAAU,UAAU,MAAM,QAAQ,GACrC,UAAU,MAAM,OAAO,CACxB;AAAA;AAAA,EAGD,OAAO,EAAE,OAAO,WAAW,SAAS;AAAA;;;AGtNrC,4BAA0B;AAW1B,yCAAwB;AACxB,gBAAS,aAAK,YAAK,WAAI,eAAI,yBAA2B;AAuC/C,SAAS,mBAAmB,CAClC,IACA,UAAgD,CAAC,GACnC;AAAA,EACd,MAAM,SAAS,QAAQ,UAAU,kBAAkB;AAAA,EACnD,OAAO;AAAA,IACN,OAAO,UAAU,IAAI,MAAM;AAAA,IAC3B,UAAU,aAAa,IAAI,MAAM;AAAA,IACjC,QAAQ,WAAW,IAAI,MAAM;AAAA,EAC9B;AAAA;AAGD,SAAS,SAAS,CAAC,IAAgB,QAAmC;AAAA,EACrE,MAAM,OAAO,CAAI,WAAmB,SACnC,IAAI,SAAS,WAAW,IAAI;AAAA,EAE7B,MAAM,OAAO,OAAO,OAAe;AAAA,IAClC,OAAO,OAAO,MAAM,GAClB,OAAO,EACP,KAAK,OAAO,KAAK,EACjB,MAAM,IAAG,OAAO,MAAM,IAAI,EAAE,CAAC;AAAA,IAC/B,OAAO,QAAQ,YAAY,OAAO,OAAO,GAAG;AAAA;AAAA,EAS7C,MAAM,QAAQ,OACb,IACA,WACA,MACA,WACI;AAAA,IAGJ,MAAM,WAAW,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,EAAE,KAAK;AAAA,IAC3C,IAAI,SAAS,WAAW;AAAA,MAAG;AAAA,IAC3B,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,MAAM,EACpB,OACA,SAAS,IAAI,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,OAAO,QAAQ,KAAK,GAAG,EAAE,CACtE,EACC,oBAAoB,EACpB,UAAU,EAAE,OAAO,OAAO,OAAO,MAAM,CAAC;AAAA,IAC1C,IAAI,QAAQ,WAAW,SAAS;AAAA,MAAQ;AAAA,IACxC,MAAM,UAAU,IAAI,IAAI,QAAQ,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;AAAA,IACvD,MAAM,QAAQ,SAAS,KAAK,CAAC,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK;AAAA,IAC/D,MAAM,WAAW,WAAW,KAAK,MAAM,KAAK;AAAA;AAAA,EAG7C,OAAO;AAAA,IACN,YAAY,CAAC,WACZ,KAAK,cAAc,YAAY;AAAA,MAC9B,MAAM,WAAW,MAAM,iBAAgB,IAAI,OAAO,OAAO;AAAA,QACxD,OAAO,OAAO,MAAM,GAClB,OAAO,OAAO,KAAK,EACnB,OAAO,UAAU,MAAM,CAAC,EACxB,oBAAoB,EAAE,QAAQ,OAAO,MAAM,GAAG,CAAC,EAC/C,UAAU;AAAA,QACZ,IAAI,QAAQ;AAAA,UAAW,OAAO;AAAA,QAC9B,MAAM,MAAM,IAAI,cAAc,QAAQ,OAAO,MAAM;AAAA,QACnD,OAAO,OAAO,GAAG;AAAA,OACjB;AAAA,MACD,IAAI,aAAa;AAAA,QAAM,OAAO;AAAA,MAI9B,MAAM,SAAS,MAAM,KAAK,OAAO,EAAE;AAAA,MACnC,IAAI,WAAW;AAAA,QAAM,OAAO;AAAA,MAE5B,MAAM,IAAI,cAAc,8CAA8C;AAAA,QACrE,QAAQ,OAAO;AAAA,QACf,WAAW;AAAA,MACZ,CAAC;AAAA,KACD;AAAA,IAEF,UAAU,CAAC,OAAO,KAAK,YAAY,MAAM,KAAK,EAAE,CAAC;AAAA,IAEjD,iBAAiB,CAAC,MAAM,UACvB,KAAK,mBAAmB,YAAY;AAAA,MACnC,OAAO,OAAO,MAAM,GAClB,OAAO,EAAE,MAAM,OAAO,MAAM,CAAC,EAC7B,KAAK,OAAO,MAAM,EAClB,UAAU,OAAO,OAAO,IAAG,OAAO,MAAM,IAAI,OAAO,OAAO,MAAM,CAAC,EACjE,MACA,KAAI,IAAG,OAAO,OAAO,MAAM,IAAI,GAAG,IAAG,OAAO,OAAO,OAAO,KAAK,CAAC,CACjE;AAAA,MACD,OAAO,QAAQ,YAAY,OAAO,OAAO,IAAI,IAAI;AAAA,KACjD;AAAA,IAEF,WAAW,GAAG,MAAM,OAAO,YAC1B,KAAK,aAAa,YAAY;AAAA,MAE7B,MAAM,QAAQ,MAAM,GAClB,OAAO,EACP,KAAK,OAAO,KAAK,EACjB,MACA,UAAU,OACP,IAAG,OAAO,MAAM,MAAM,IAAI,IAC1B,KAAI,IAAG,OAAO,MAAM,MAAM,IAAI,GAAG,IAAG,OAAO,MAAM,IAAI,KAAK,CAAC,CAC/D,EACC,QAAQ,KAAI,OAAO,MAAM,EAAE,CAAC,EAC5B,MAAM,QAAQ,CAAC;AAAA,MACjB,MAAM,QAAQ,MAAM,MAAM,GAAG,KAAK,EAAE,IAAI,MAAM;AAAA,MAC9C,MAAM,OAAO,MAAM,GAAG,EAAE;AAAA,MACxB,OAAO;AAAA,QACN;AAAA,QACA,YACC,MAAM,SAAS,SAAS,SAAS,YAAY,KAAK,KAAK;AAAA,MACzD;AAAA,KACA;AAAA,IAEF,YAAY,CAAC,IAAI,OAAO,cACvB,KAAK,cAAc,MAClB,iBAAgB,IAAI,OAAO,OAAO;AAAA,MACjC,OAAO,OAAO,MAAM,GAClB,OAAO,OAAO,KAAK,EACnB,IAAI;AAAA,WACD,UAAU,KAAK;AAAA,QAClB,SAAS,OAAM,OAAO,MAAM;AAAA,MAC7B,CAAC,EACA,MACA,KAAI,IAAG,OAAO,MAAM,IAAI,EAAE,GAAG,IAAG,OAAO,MAAM,SAAS,SAAS,CAAC,CACjE,EACC,UAAU;AAAA,MAEZ,IAAI,QAAQ,WAAW;AAAA,QAGtB,OAAO,UAAU,MAAM,GACrB,OAAO,EAAE,SAAS,OAAO,MAAM,QAAQ,CAAC,EACxC,KAAK,OAAO,KAAK,EACjB,MAAM,IAAG,OAAO,MAAM,IAAI,EAAE,CAAC;AAAA,QAC/B,IAAI,WAAW,WAAW;AAAA,UACzB,MAAM,IAAI,cAAc,mCAAmC;AAAA,YAC1D,QAAQ;AAAA,YACR,WAAW;AAAA,UACZ,CAAC;AAAA,QACF;AAAA,QACA,MAAM,IAAI,eACT,WACA,gCAAgC,oBAAoB,OAAO,WAC3D;AAAA,UACC,QAAQ;AAAA,UACR,iBAAiB;AAAA,UACjB,eAAe,OAAO;AAAA,UACtB,WAAW;AAAA,QACZ,CACD;AAAA,MACD;AAAA,MAEA,IAAI,MAAM,WAAW,WAAW;AAAA,QAC/B,MAAM,GAAG,OAAO,OAAO,MAAM,EAAE,MAAM,IAAG,OAAO,OAAO,QAAQ,EAAE,CAAC;AAAA,QACjE,MAAM,MAAM,IAAI,cAAc,KAAK,MAAM,MAAM;AAAA,MAChD;AAAA,MACA,OAAO,OAAO,GAAG;AAAA,KACjB,CACF;AAAA,IAED,YAAY,CAAC,OACZ,KAAK,cAAc,YAAY;AAAA,MAE9B,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,KAAK,EACnB,MAAM,IAAG,OAAO,MAAM,IAAI,EAAE,CAAC,EAC7B,UAAU,EAAE,IAAI,OAAO,MAAM,GAAG,CAAC;AAAA,MACnC,OAAO,QAAQ,WAAW;AAAA,KAC1B;AAAA,EACH;AAAA;AAGD,SAAS,YAAY,CAAC,IAAgB,QAAsC;AAAA,EAC3E,MAAM,OAAO,CAAI,WAAmB,SACnC,IAAI,YAAY,WAAW,IAAI;AAAA,EAEhC,OAAO;AAAA,IACN,eAAe,CAAC,WACf,KAAK,iBAAiB,YAAY;AAAA,MAGjC,MAAM,GACJ,OAAO,OAAO,QAAQ,EACtB,OAAO,MAAM,EACb,oBAAoB,EAAE,QAAQ,OAAO,SAAS,GAAG,CAAC;AAAA,KACpD;AAAA,IAEF,wBAAwB,CAAC,cACxB,KAAK,0BAA0B,YAAY;AAAA,MAC1C,OAAO,OAAO,MAAM,GAClB,OAAO,EACP,KAAK,OAAO,QAAQ,EACpB,MAAM,IAAG,OAAO,SAAS,WAAW,SAAS,CAAC;AAAA,MAChD,OAAO,QAAQ,YAAY,OAAO,UAAU,GAAG;AAAA,KAC/C;AAAA,IAEF,eAAe,CAAC,IAAI,cACnB,KAAK,iBAAiB,YAAY;AAAA,MAGjC,OAAO,OAAO,MAAM,GAClB,OAAO,OAAO,QAAQ,EACtB,IAAI,EAAE,UAAU,CAAC,EACjB,MACA,KAAI,IAAG,OAAO,SAAS,IAAI,EAAE,GAAG,QAAO,OAAO,SAAS,SAAS,CAAC,CAClE,EACC,UAAU;AAAA,MACZ,OAAO,QAAQ,YAAY,OAAO,UAAU,GAAG;AAAA,KAC/C;AAAA,IAEF,eAAe,CAAC,IAAI,OACnB,KAAK,iBAAiB,YAAY;AAAA,MAGjC,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,QAAQ,EACtB,IAAI;AAAA,QACJ,WAAW,gBAAe,OAAO,SAAS,cAAc,MAAM,EAAE;AAAA,MACjE,CAAC,EACA,MAAM,IAAG,OAAO,SAAS,IAAI,EAAE,CAAC,EAChC,UAAU,EAAE,IAAI,OAAO,SAAS,GAAG,CAAC;AAAA,MACtC,OAAO,QAAQ,WAAW;AAAA,KAC1B;AAAA,IAEF,oBAAoB,CAAC,QAAQ,IAAI,WAChC,KAAK,sBAAsB,YAAY;AAAA,MACtC,MAAM,WAAW,KAChB,IAAG,OAAO,SAAS,QAAQ,MAAM,GACjC,QAAO,OAAO,SAAS,SAAS,CACjC;AAAA,MACA,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,QAAQ,EACtB,IAAI,EAAE,WAAW,GAAG,CAAC,EACrB,MACA,WAAW,YACR,WACA,KAAI,UAAU,GAAG,OAAO,SAAS,IAAI,MAAM,CAAC,CAChD,EACC,UAAU,EAAE,IAAI,OAAO,SAAS,GAAG,CAAC;AAAA,MACtC,OAAO,QAAQ;AAAA,KACf;AAAA,IAEF,oBAAoB,CAAC,WACpB,KAAK,sBAAsB,YAAY;AAAA,MACtC,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,QAAQ,EACtB,MAAM,IAAG,OAAO,SAAS,QAAQ,MAAM,CAAC,EACxC,UAAU,EAAE,IAAI,OAAO,SAAS,GAAG,CAAC;AAAA,MACtC,OAAO,QAAQ;AAAA,KACf;AAAA,IAEF,uBAAuB,CAAC,WACvB,KAAK,yBAAyB,YAAY;AAAA,MACzC,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,QAAQ,EACtB,MAAM,IAAI,OAAO,SAAS,WAAW,MAAM,CAAC,EAC5C,UAAU,EAAE,IAAI,OAAO,SAAS,GAAG,CAAC;AAAA,MACtC,OAAO,QAAQ;AAAA,KACf;AAAA,EACH;AAAA;AAGD,SAAS,UAAU,CAAC,IAAgB,QAAoC;AAAA,EACvE,MAAM,OAAO,CAAI,WAAmB,SACnC,IAAI,UAAU,WAAW,IAAI;AAAA,EAE9B,OAAO;AAAA,IACN,aAAa,CAAC,WACb,KAAK,eAAe,YAAY;AAAA,MAE/B,MAAM,GAAG,OAAO,OAAO,MAAM,EAAE,OAAO,MAAM,EAAE,oBAAoB;AAAA,KAClE;AAAA,IAEF,cAAc,CAAC,WAAW,MAAM,OAC/B,KAAK,gBAAgB,YAAY;AAAA,MAKhC,MAAM,SAAS,GAAG,MAAM,QAAQ,EAAE,GACjC,GACE,OAAO,EACP,KAAK,OAAO,MAAM,EAClB,MACA,KACC,IAAG,OAAO,OAAO,WAAW,SAAS,GACrC,IAAG,OAAO,OAAO,MAAM,IAAI,CAC5B,CACD,EACC,IAAI,QAAQ,CACf;AAAA,MACA,OAAO,SAAS,MAAM,GACpB,KAAK,MAAM,EACX,OAAO,OAAO,MAAM,EACpB,IAAI;AAAA,QACJ,SAAS,gBAAe,OAAO,OAAO,YAAY,MAAM,EAAE;AAAA,MAC3D,CAAC,EACA,KAAK,MAAM,EACX,MAAM,IAAG,OAAO,OAAO,WAAW,OAAO,SAAS,CAAC,EACnD,UAAU;AAAA,QACV,WAAW,OAAO;AAAA,QAClB,MAAM,OAAO;AAAA,QACb,QAAQ,OAAO;AAAA,QACf,SAAS,OAAO;AAAA,QAChB,UAAU,OAAO;AAAA,QACjB,UAAU,OAAO;AAAA,QACjB,WAAW,OAAO;AAAA,QAClB,SAAS,OAAO;AAAA,QAChB,WAAW,OAAO;AAAA,MACnB,CAAC;AAAA,MACF,OAAO,UAAU,YACd,OACA,KAAK,OAAO,QAAQ,MAAM,OAAa;AAAA,KAC1C;AAAA,IAEF,cAAc,CAAC,WAAW,SACzB,KAAK,gBAAgB,YAAY;AAAA,MAIhC,MAAM,QAAQ,KACb,IAAG,OAAO,OAAO,WAAW,SAAS,GACrC,IAAG,OAAO,OAAO,MAAM,IAAI,CAC5B;AAAA,MACA,OAAO,WAAW,MAAM,GACtB,OAAO,OAAO,MAAM,EACpB,IAAI,EAAE,UAAU,OAAM,OAAO,OAAO,eAAe,CAAC,EACpD,MAAM,KAAI,OAAO,QAAO,OAAO,OAAO,OAAO,CAAC,CAAC,EAC/C,UAAU;AAAA,MACZ,MAAM,MACL,YAAY,MAAM,GAAG,OAAO,EAAE,KAAK,OAAO,MAAM,EAAE,MAAM,KAAK,GAAG;AAAA,MACjE,OAAO,QAAQ,YAAY,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAa;AAAA,KACrE;AAAA,IAEF,iBAAiB,CAAC,QAAQ,MAAM,IAAI,WACnC,KAAK,mBAAmB,YAAY;AAAA,MAInC,MAAM,QAAQ,MAAM,GAClB,OAAO,OAAO,MAAM,EACpB,IAAI,EAAE,SAAS,GAAG,CAAC,EACnB,MACA,KACC,IAAG,OAAO,OAAO,QAAQ,MAAM,GAC/B,IAAG,OAAO,OAAO,MAAM,IAAI,GAC3B,QAAO,OAAO,OAAO,OAAO,GAC5B,WAAW,YACR,YACA,GAAG,OAAO,OAAO,WAAW,MAAM,CACtC,CACD,EACC,UAAU,EAAE,WAAW,OAAO,OAAO,UAAU,CAAC;AAAA,MAClD,OAAO,MAAM;AAAA,KACb;AAAA,IAEF,kBAAkB,CAAC,WAClB,KAAK,oBAAoB,YAAY;AAAA,MACpC,MAAM,UAAU,MAAM,GACpB,OAAO,OAAO,MAAM,EACpB,MAAM,IAAG,OAAO,OAAO,QAAQ,MAAM,CAAC,EACtC,UAAU,EAAE,WAAW,OAAO,OAAO,UAAU,CAAC;AAAA,MAClD,OAAO,QAAQ;AAAA,KACf;AAAA,EACH;AAAA;AAQD,SAAS,SAAS,CAAC,QAAgC;AAAA,EAClD,OAAO;AAAA,IACN,IAAI,OAAO;AAAA,IACX,MAAM,OAAO;AAAA,IACb,eAAe,OAAO;AAAA,IACtB,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,QAAQ,CAAC,GAAG,OAAO,MAAM;AAAA,IACzB,cAAc,OAAO,UAAU,QAAQ;AAAA,IACvC,mBAAmB,OAAO,UAAU,aAAa;AAAA,OAC9C,sBAAsB,OAAO,YAAY;AAAA,IAC5C,iBAAiB,OAAO;AAAA,IACxB,SAAS,OAAO;AAAA,IAChB,WAAW,OAAO;AAAA,IAClB,WAAW,OAAO;AAAA,EACnB;AAAA;AAQD,SAAS,SAAS,CAAC,OAAuC;AAAA,EACzD,MAAM,MAA2B;AAAA,IAChC,WAAW,MAAM;AAAA,EAClB;AAAA,EACA,IAAI,MAAM,kBAAkB;AAAA,IAC3B,IAAI,gBAAgB,MAAM;AAAA,EAC3B,IAAI,MAAM,WAAW;AAAA,IAAW,IAAI,SAAS,MAAM;AAAA,EACnD,IAAI,MAAM,WAAW;AAAA,IAAW,IAAI,SAAS,MAAM;AAAA,EACnD,IAAI,MAAM,WAAW;AAAA,IAAW,IAAI,SAAS,CAAC,GAAG,MAAM,MAAM;AAAA,EAC7D,IAAI,MAAM,oBAAoB;AAAA,IAC7B,IAAI,kBAAkB,MAAM;AAAA,EAC7B,IAAI,MAAM,aAAa,WAAW;AAAA,IACjC,IAAI,eAAe,MAAM,UAAU,QAAQ;AAAA,IAC3C,IAAI,oBAAoB,MAAM,UAAU,aAAa;AAAA,EACtD;AAAA,EACA,IAAI,MAAM,iBAAiB,WAAW;AAAA,IACrC,OAAO,OAAO,KAAK,sBAAsB,MAAM,YAAY,CAAC;AAAA,EAC7D;AAAA,EACA,OAAO;AAAA;AAIR,SAAS,qBAAqB,CAAC,cAA0C;AAAA,EACxE,OAAO;AAAA,IACN,oBAAoB,cAAc,UAAU;AAAA,IAC5C,oBAAoB,cAAc,UAAU;AAAA,IAC5C,yBAAyB,cAAc,eAAe;AAAA,IACtD,sBAAsB,cAAc,YAAY;AAAA,EACjD;AAAA;AAGD,SAAS,MAAM,CAAC,KAA0B;AAAA,EACzC,OAAO;AAAA,IACN,IAAI,IAAI;AAAA,IACR,MAAM,IAAI;AAAA,IACV,eAAe,IAAI;AAAA,IACnB,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,QAAQ,CAAC,GAAG,IAAI,MAAM;AAAA,IACtB,UACC,IAAI,iBAAiB,QAAQ,IAAI,sBAAsB,OACpD,OACA,EAAE,MAAM,IAAI,cAAc,WAAW,IAAI,kBAAkB;AAAA,IAC/D,cACC,IAAI,uBAAuB,QAAQ,IAAI,uBAAuB,OAC3D,OACA;AAAA,MACA,QAAQ,IAAI;AAAA,MACZ,QAAQ,IAAI;AAAA,MACZ,aAAa,IAAI;AAAA,MACjB,UAAU,IAAI;AAAA,IACf;AAAA,IACH,iBAAiB,IAAI;AAAA,IACrB,SAAS,IAAI;AAAA,IACb,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,EAChB;AAAA;AAGD,SAAS,SAAS,CAAC,KAAgC;AAAA,EAClD,OAAO;AAAA,IACN,IAAI,IAAI;AAAA,IACR,WAAW,IAAI;AAAA,IACf,QAAQ,IAAI;AAAA,IACZ,iBAAiB,IAAI;AAAA,IACrB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,EAChB;AAAA;AAQD,SAAS,KAAK,CAAC,IAAe;AAAA,EAC7B,OAAO,OAAM,GAAG,YAAY;AAAA;;;AC9etB,SAAS,oBAAoB,CACnC,IACA,UAAiC,CAAC,GACjB;AAAA,EACjB,OAAO;AAAA,IACN,OAAO,oBAAoB,IAAI,OAAO;AAAA,IACtC,WAAW,uBAAuB,IAAI,OAAO;AAAA,EAC9C;AAAA;",
|
|
12
|
-
"debugId": "
|
|
25
|
+
"mappings": "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",
|
|
26
|
+
"debugId": "3F6F0185055BC57C64756E2164756E21",
|
|
13
27
|
"names": []
|
|
14
28
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PgDatabase } from '@nxgt/drizzle/pg';
|
|
2
|
+
import type { JanusTables } from '../tables';
|
|
3
|
+
export type Relations = JanusTables['relations'];
|
|
4
|
+
/** What every step queries: the database, and the `relations` table in use. */
|
|
5
|
+
export interface RelationContext {
|
|
6
|
+
readonly db: PgDatabase;
|
|
7
|
+
readonly relations: Relations;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/relations/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,MAAM,SAAS,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;AAEjD,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC9B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PgDatabase } from '@nxgt/drizzle/pg';
|
|
2
2
|
import type { RelationStore } from '@nxgt/janus/permissions';
|
|
3
|
-
import { type DrizzleAdapterOptions } from '
|
|
3
|
+
import { type DrizzleAdapterOptions } from '../tables';
|
|
4
4
|
/**
|
|
5
5
|
* The relation store `permissions()` takes, over one PostgreSQL database
|
|
6
6
|
* through Drizzle — and the one `janus({ relations })` deletes a user's
|
|
@@ -15,4 +15,4 @@ import { type DrizzleAdapterOptions } from './tables';
|
|
|
15
15
|
* retried here — a write is idempotent, so the caller retries.
|
|
16
16
|
*/
|
|
17
17
|
export declare function createDrizzleRelations(db: PgDatabase, options?: DrizzleAdapterOptions<'relations'>): RelationStore;
|
|
18
|
-
//# sourceMappingURL=
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/relations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,KAAK,qBAAqB,EAAqB,MAAM,WAAW,CAAC;AAM1E;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACrC,EAAE,EAAE,UAAU,EACd,OAAO,GAAE,qBAAqB,CAAC,WAAW,CAAM,GAC9C,aAAa,CAwBf"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CursorPage, Entity, RelationTuple, SubjectSet } from '@nxgt/janus';
|
|
2
|
+
import type { ObjectPageRequest } from '@nxgt/janus/permissions';
|
|
3
|
+
import type { RelationContext } from './context';
|
|
4
|
+
export declare function has({ db, relations }: RelationContext, tuple: RelationTuple): Promise<boolean>;
|
|
5
|
+
export declare function findSubjectSets(context: RelationContext, object: Entity, relation: string): Promise<SubjectSet[]>;
|
|
6
|
+
export declare function findEntities(context: RelationContext, object: Entity, relation: string): Promise<Entity[]>;
|
|
7
|
+
/** A page of object ids, in id order, after the cursor. */
|
|
8
|
+
export declare function findObjects({ db, relations }: RelationContext, { type, relation, subject, after, limit }: ObjectPageRequest): Promise<CursorPage<string>>;
|
|
9
|
+
//# sourceMappingURL=reads.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../../src/relations/reads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,UAAU,EACV,MAAM,EACN,aAAa,EACb,UAAU,EACV,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAGjD,wBAAsB,GAAG,CACxB,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,eAAe,EAClC,KAAK,EAAE,aAAa,GAClB,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAsB,eAAe,CACpC,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,EAAE,CAAC,CAQvB;AAED,wBAAsB,YAAY,CACjC,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,EAAE,CAAC,CAInB;AA4BD,2DAA2D;AAC3D,wBAAsB,WAAW,CAChC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,eAAe,EAClC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,iBAAiB,GAC1D,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAmB7B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RelationTuple, type Subject } from '@nxgt/janus';
|
|
2
|
+
import { type SQL } from 'drizzle-orm';
|
|
3
|
+
import type { Relations } from './context';
|
|
4
|
+
/** Tuples in one order: their notation, compared by code unit. */
|
|
5
|
+
export declare function inOrder(tuples: readonly RelationTuple[]): readonly RelationTuple[];
|
|
6
|
+
/** A tuple as a row: an entity's `subject_relation` is `null`. */
|
|
7
|
+
export declare function rowOf(tuple: RelationTuple): Relations['$inferInsert'];
|
|
8
|
+
/** Exactly this subject: a subject set is not its entity, and the reverse. */
|
|
9
|
+
export declare function subjectIs(relations: Relations, subject: Subject): SQL | undefined;
|
|
10
|
+
/** Exactly this tuple. */
|
|
11
|
+
export declare function matching(relations: Relations, tuple: RelationTuple): SQL | undefined;
|
|
12
|
+
//# sourceMappingURL=tuples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tuples.d.ts","sourceRoot":"","sources":["../../src/relations/tuples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAmB,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,kEAAkE;AAClE,wBAAgB,OAAO,CACtB,MAAM,EAAE,SAAS,aAAa,EAAE,GAC9B,SAAS,aAAa,EAAE,CAc1B;AAED,kEAAkE;AAClE,wBAAgB,KAAK,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,CAAC,cAAc,CAAC,CAWrE;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CACxB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,GACd,GAAG,GAAG,SAAS,CAQjB;AAED,0BAA0B;AAC1B,wBAAgB,QAAQ,CACvB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,aAAa,GAClB,GAAG,GAAG,SAAS,CAOjB"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Entity, RelationTuple } from '@nxgt/janus';
|
|
2
|
+
import type { RelationContext } from './context';
|
|
3
|
+
/** One tuple in one statement; more in one transaction. */
|
|
4
|
+
export declare function write({ db, relations }: RelationContext, add: readonly RelationTuple[], remove: readonly RelationTuple[]): Promise<void>;
|
|
5
|
+
/** Every tuple naming the entity, as object or as subject. */
|
|
6
|
+
export declare function deleteEntity({ db, relations }: RelationContext, entity: Entity): Promise<number>;
|
|
7
|
+
//# sourceMappingURL=writes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writes.d.ts","sourceRoot":"","sources":["../../src/relations/writes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,KAAK,EAAE,eAAe,EAAa,MAAM,WAAW,CAAC;AAG5D,2DAA2D;AAC3D,wBAAsB,KAAK,CAC1B,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,eAAe,EAClC,GAAG,EAAE,SAAS,aAAa,EAAE,EAC7B,MAAM,EAAE,SAAS,aAAa,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CAGf;AAuBD,8DAA8D;AAC9D,wBAAsB,YAAY,CACjC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,eAAe,EAClC,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { JanusTables } from '../tables';
|
|
2
|
+
/** The four tables the identity stores query. */
|
|
3
|
+
export type IdentityTable = 'users' | 'logins' | 'sessions' | 'tokens';
|
|
4
|
+
export type IdentityTables = Pick<JanusTables, IdentityTable>;
|
|
5
|
+
//# sourceMappingURL=identity-tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity-tables.d.ts","sourceRoot":"","sources":["../../src/stores/identity-tables.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,iDAAiD;AACjD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;AACvE,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { PgDatabase } from '@nxgt/drizzle/pg';
|
|
2
2
|
import type { JanusStores } from '@nxgt/janus';
|
|
3
|
-
import { type DrizzleAdapterOptions } from '
|
|
4
|
-
|
|
5
|
-
type IdentityTable = 'users' | 'logins' | 'sessions' | 'tokens';
|
|
3
|
+
import { type DrizzleAdapterOptions } from '../tables';
|
|
4
|
+
import type { IdentityTable } from './identity-tables';
|
|
6
5
|
/**
|
|
7
6
|
* The three stores `janus()` takes, over one PostgreSQL database through
|
|
8
7
|
* Drizzle.
|
|
@@ -27,5 +26,4 @@ type IdentityTable = 'users' | 'logins' | 'sessions' | 'tokens';
|
|
|
27
26
|
* connection's `search_path`.
|
|
28
27
|
*/
|
|
29
28
|
export declare function createDrizzleStores(db: PgDatabase, options?: DrizzleAdapterOptions<IdentityTable>): JanusStores;
|
|
30
|
-
|
|
31
|
-
//# sourceMappingURL=stores.d.ts.map
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,KAAK,qBAAqB,EAAqB,MAAM,WAAW,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAKvD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CAClC,EAAE,EAAE,UAAU,EACd,OAAO,GAAE,qBAAqB,CAAC,aAAa,CAAM,GAChD,WAAW,CAOb"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PgDatabase } from '@nxgt/drizzle/pg';
|
|
2
|
+
import type { IdentityTables } from './identity-tables';
|
|
3
|
+
/**
|
|
4
|
+
* Writes the logins of one user, and throws the port's conflict for the
|
|
5
|
+
* first one another user of the type holds. `on conflict do nothing`: a
|
|
6
|
+
* login the statement did not write is one somebody else holds, and a
|
|
7
|
+
* concurrent sign-up waits for the first to commit, then writes nothing.
|
|
8
|
+
*/
|
|
9
|
+
export declare function claimLogins(tx: PgDatabase, tables: IdentityTables, operation: string, user: {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly type: string;
|
|
12
|
+
}, logins: readonly string[]): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=logins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logins.d.ts","sourceRoot":"","sources":["../../src/stores/logins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;GAKG;AACH,wBAAsB,WAAW,CAChC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpD,MAAM,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SessionRecord, UserPatch, UserRecord } from '@nxgt/janus';
|
|
2
|
+
import { type SQL } from 'drizzle-orm';
|
|
3
|
+
import type { JanusTables } from '../tables';
|
|
4
|
+
type UserRow = JanusTables['users']['$inferSelect'];
|
|
5
|
+
type UserInsert = JanusTables['users']['$inferInsert'];
|
|
6
|
+
type SessionRow = JanusTables['sessions']['$inferSelect'];
|
|
7
|
+
export declare function toUserRow(record: UserRecord): UserInsert;
|
|
8
|
+
/**
|
|
9
|
+
* The columns a patch names. A key present with `undefined` is absent, as the
|
|
10
|
+
* port says — never an erasure. `password: null` is named, and removes the
|
|
11
|
+
* password.
|
|
12
|
+
*/
|
|
13
|
+
export declare function toUserSet(patch: UserPatch): Partial<UserInsert>;
|
|
14
|
+
export declare function toUser(row: UserRow): UserRecord;
|
|
15
|
+
export declare function toSession(row: SessionRow): SessionRecord;
|
|
16
|
+
/**
|
|
17
|
+
* A `Date` inside a `sql` template, as every driver takes it: `timestamptz`
|
|
18
|
+
* from its ISO string. Drizzle's column mapping does not reach a raw
|
|
19
|
+
* template, and postgres.js refuses a `Date` object there.
|
|
20
|
+
*/
|
|
21
|
+
export declare function stamp(at: Date): SQL;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=records.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../src/stores/records.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAM,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,KAAK,GAAG,EAAO,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAO7C,KAAK,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC;AACpD,KAAK,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,CAAC;AACvD,KAAK,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,CAAC;AAE1D,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAgBxD;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAmB/D;AAYD,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CA0B/C;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,aAAa,CAUxD;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,IAAI,GAAG,GAAG,CAEnC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PgDatabase } from '@nxgt/drizzle/pg';
|
|
2
|
+
import type { SessionStore } from '@nxgt/janus';
|
|
3
|
+
import type { IdentityTables } from './identity-tables';
|
|
4
|
+
export declare function sessionStore(db: PgDatabase, tables: IdentityTables): SessionStore;
|
|
5
|
+
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/stores/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,wBAAgB,YAAY,CAC3B,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,cAAc,GACpB,YAAY,CAgEd"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PgDatabase } from '@nxgt/drizzle/pg';
|
|
2
|
+
import type { TokenStore } from '@nxgt/janus';
|
|
3
|
+
import type { IdentityTables } from './identity-tables';
|
|
4
|
+
export declare function tokenStore(db: PgDatabase, tables: IdentityTables): TokenStore;
|
|
5
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/stores/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAA8B,UAAU,EAAE,MAAM,aAAa,CAAC;AAG1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,wBAAgB,UAAU,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,GAAG,UAAU,CAgD7E"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type PgDatabase } from '@nxgt/drizzle/pg';
|
|
2
|
+
import type { UserStore } from '@nxgt/janus';
|
|
3
|
+
import type { IdentityTables } from './identity-tables';
|
|
4
|
+
export declare function userStore(db: PgDatabase, tables: IdentityTables): UserStore;
|
|
5
|
+
//# sourceMappingURL=users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/stores/users.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAmB,MAAM,kBAAkB,CAAC;AACpE,OAAO,KAAK,EAAyB,SAAS,EAAE,MAAM,aAAa,CAAC;AAIpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,wBAAgB,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,GAAG,SAAS,CA6D3E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type pgTable } from 'drizzle-orm/pg-core';
|
|
2
|
+
/** `pgTable`, or the `table` of the schema the tables live in. */
|
|
3
|
+
export type TableFactory = typeof pgTable;
|
|
4
|
+
/**
|
|
5
|
+
* A key compared byte by byte, as the port asks (rule 4): `collate "C"`. Under
|
|
6
|
+
* a database's default collation, `en_US.UTF-8` or the like, `B` sorts after
|
|
7
|
+
* `a` — and a page in "ascending id order" repeats or skips rows.
|
|
8
|
+
*/
|
|
9
|
+
export declare const key: {
|
|
10
|
+
<TConfig extends Record<string, any>>(fieldConfig?: TConfig | undefined): import("drizzle-orm/pg-core").PgCustomColumnBuilder<{
|
|
11
|
+
dataType: "custom";
|
|
12
|
+
data: string;
|
|
13
|
+
driverParam: string;
|
|
14
|
+
}>;
|
|
15
|
+
(dbName: string, fieldConfig?: unknown): import("drizzle-orm/pg-core").PgCustomColumnBuilder<{
|
|
16
|
+
dataType: "custom";
|
|
17
|
+
data: string;
|
|
18
|
+
driverParam: string;
|
|
19
|
+
}>;
|
|
20
|
+
};
|
|
21
|
+
export declare const at: (name: string) => import("drizzle-orm/pg-core").PgTimestampBuilder;
|
|
22
|
+
//# sourceMappingURL=columns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns.d.ts","sourceRoot":"","sources":["../../src/tables/columns.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,OAAO,EAAa,MAAM,qBAAqB,CAAC;AAE1E,kEAAkE;AAClE,MAAM,MAAM,YAAY,GAAG,OAAO,OAAO,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,GAAG;;;;;;;;;;;CAEd,CAAC;AAKH,eAAO,MAAM,EAAE,GAAI,MAAM,MAAM,qDACuB,CAAC"}
|
|
@@ -781,4 +781,4 @@ export type JanusTables = ReturnType<typeof defineJanusTables>;
|
|
|
781
781
|
export interface DrizzleAdapterOptions<K extends keyof JanusTables = keyof JanusTables> {
|
|
782
782
|
readonly tables?: Pick<JanusTables, K>;
|
|
783
783
|
}
|
|
784
|
-
//# sourceMappingURL=
|
|
784
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tables/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAW,MAAM,qBAAqB,CAAC;AAQ7D;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,6BAA6B;AAC7B,MAAM,WAAW,kBAAkB;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASjE;AAED,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE/D;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,qBAAqB,CACrC,CAAC,SAAS,MAAM,WAAW,GAAG,MAAM,WAAW;IAE/C,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;CACvC"}
|