@flaredev/core 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -125,6 +125,22 @@ interface StorageBucket {
125
125
  };
126
126
  }): Promise<unknown>;
127
127
  delete(keys: string | string[]): Promise<void>;
128
+ /**
129
+ * The keys in the bucket, a page at a time. R2 counts this as a Class A operation —
130
+ * the expensive kind — so call it to answer a question, not on a page people reload.
131
+ */
132
+ list?(options?: {
133
+ limit?: number;
134
+ prefix?: string;
135
+ cursor?: string;
136
+ }): Promise<{
137
+ objects: {
138
+ key: string;
139
+ size: number;
140
+ }[];
141
+ truncated: boolean;
142
+ cursor?: string;
143
+ }>;
128
144
  }
129
145
  interface StorageObjectBody {
130
146
  body: ReadableStream;
@@ -497,7 +513,11 @@ declare const fake: Fake;
497
513
  */
498
514
  type InsertMany = <T extends object>(table: unknown, count: number | readonly T[], build?: (index: number) => T) => Promise<number>;
499
515
  interface SeedContext {
500
- /** Drizzle client over the app's schema, bound to the local D1 database. */
516
+ /**
517
+ * The app's database client: Drizzle over the local D1 database on Cloudflare, the
518
+ * app's own Prisma client on Next.js. Untyped, because which one it is depends on
519
+ * the stack and both are generated per app.
520
+ */
501
521
  db: any;
502
522
  /** All local bindings and variables (D1, R2, .dev.vars). */
503
523
  env: Record<string, unknown>;
@@ -509,6 +529,6 @@ interface SeedContext {
509
529
  type Seed = (context: SeedContext) => void | Promise<void>;
510
530
  declare function defineSeed(seed: Seed): Seed;
511
531
 
512
- declare const FLARE_VERSION = "0.4.1";
532
+ declare const FLARE_VERSION = "0.5.0";
513
533
 
514
534
  export { type BelongsToRelation, type Country, CreateInput, FLARE_VERSION, type Fake, Field, type FormValues, type FormatOptions, type HasManyRelation, type InsertMany, type MailMessage, type MailResult, type Mailer, type MailerOptions, PBKDF2_ITERATIONS, type ReadUrlOptions, RelationError, type RelationGraph, Resource, type ResourceRelations, type ResourceValidators, SNIFF_BYTES, SUBSCRIPTION_STATUSES, type Seed, type SeedContext, type Storage, type StorageBucket, type StorageOptions, StoredField, type SubscriptionLike, type SubscriptionState, type SubscriptionStatus, type Tone, type TransactionalEmail, UpdateInput, type UploadUrlOptions, camelCase, checkoutPaid, countries, countryName, createFake, createMailer, createObjectKey, createStorage, createValidators, currentPeriodEnd, defineSeed, fake, fieldSchema, fileKeyPrefix, flagEmoji, formValuesToInput, formatPhone, formatValue, grantsAccess, hashPassword, humanize, importSigningKey, initialFormValues, isColor, isCountryCode, isDomain, isLiveSubscription, isPhoneNumber, isSlug, issuesByField, kebabCase, matchesContentType, normalizeDomain, optionLabel, parseMultiValue, pascalCase, pluralize, randomLetters, relationGraph, renderTransactionalEmail, shouldApplySubscription, signToken, slugify, snakeCase, sniffMatches, splitPhone, statusTone, subscriptionPriceId, subscriptionState, toE164, toSubscriptionStatus, verifyPassword, verifyToken, words };
package/dist/index.js CHANGED
@@ -994,7 +994,7 @@ function createFake(seed = 20260101) {
994
994
  var fake = createFake();
995
995
 
996
996
  // src/index.ts
997
- var FLARE_VERSION = "0.4.1";
997
+ var FLARE_VERSION = "0.5.0";
998
998
  export {
999
999
  DEFAULT_FILE_MAX_BYTES,
1000
1000
  FILE_CATEGORIES,
package/dist/server.d.ts CHANGED
@@ -1,7 +1,83 @@
1
1
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
2
- import { BaseSQLiteDatabase, SQLiteTable } from 'drizzle-orm/sqlite-core';
2
+ import { BaseSQLiteDatabase, SQLiteTable, SQLiteColumn } from 'drizzle-orm/sqlite-core';
3
3
  import { S as StoredField, R as Resource, F as Field, P as Policy } from './policy-DaKcWZ5g.js';
4
4
 
5
+ /**
6
+ * The handful of things a resource store needs a database to do.
7
+ *
8
+ * Everything that makes a Flare resource behave the way it does — validation, hooks,
9
+ * computed values, cursors, capped counts, the wording of a constraint error — lives in
10
+ * the store and is the same on every stack. What differs is how rows are actually read
11
+ * and written, and that is this interface: nine operations, described in the
12
+ * descriptor's terms rather than in SQL.
13
+ *
14
+ * Drizzle over SQLite is one implementation; Prisma over Postgres is another. A store
15
+ * built on either behaves identically, which is the whole point — the same descriptor
16
+ * has to mean the same thing on Cloudflare and on Vercel.
17
+ */
18
+ type Row = Record<string, unknown>;
19
+ /** What a list needs, before it becomes SQL. */
20
+ interface RowsQuery {
21
+ /** Free-text search across the fields the descriptor marks searchable. */
22
+ search?: {
23
+ term: string;
24
+ fields: string[];
25
+ };
26
+ /** field → value, or null for "is null". */
27
+ filters: Record<string, unknown>;
28
+ sort: {
29
+ field: string;
30
+ direction: "asc" | "desc";
31
+ };
32
+ /**
33
+ * Keyset pagination: everything after (or before) this row, compared on
34
+ * `(sort field, id)` together so rows sharing a sort value are neither skipped nor
35
+ * repeated.
36
+ */
37
+ cursor?: {
38
+ field: string;
39
+ value: unknown;
40
+ id: string;
41
+ greaterThan: boolean;
42
+ };
43
+ limit: number;
44
+ /** Offset paging, for the page-number case. Never combined with a cursor. */
45
+ offset?: number;
46
+ }
47
+ /** A database refusing a write, in terms the store can turn into a message. */
48
+ type ConstraintHit = {
49
+ kind: "unique";
50
+ column?: string;
51
+ } | {
52
+ kind: "foreignKey";
53
+ } | {
54
+ kind: "check";
55
+ };
56
+ interface ResourceRows {
57
+ /** The database handle a descriptor's hooks are given. Drizzle, or a Prisma client. */
58
+ readonly db: unknown;
59
+ find(query: RowsQuery): Promise<Row[]>;
60
+ /** How many rows match, giving up at `limit` so a huge table is never fully counted. */
61
+ countUpTo(query: Pick<RowsQuery, "search" | "filters">, limit: number): Promise<number>;
62
+ byId(id: string): Promise<Row | null>;
63
+ titles(ids: string[], titleField: string): Promise<{
64
+ id: string;
65
+ title: unknown;
66
+ }[]>;
67
+ insert(values: Row): Promise<Row>;
68
+ /** The saved row, or null when there was nothing with that id. */
69
+ update(id: string, values: Row): Promise<Row | null>;
70
+ /** Whether a row was actually removed. */
71
+ remove(id: string): Promise<boolean>;
72
+ /** Recognise a constraint violation, or hand the error back by returning undefined. */
73
+ constraint(error: unknown): ConstraintHit | undefined;
74
+ }
75
+
76
+ type AnyDatabase = BaseSQLiteDatabase<"sync" | "async", any, any>;
77
+ declare function drizzleRows(table: SQLiteTable, getDb: () => AnyDatabase): ResourceRows & {
78
+ columns: Record<string, SQLiteColumn>;
79
+ };
80
+
5
81
  interface ListQuery {
6
82
  page: number;
7
83
  perPage: number;
@@ -44,7 +120,6 @@ declare function parseListQuery(resource: Resource, params: URLSearchParams): {
44
120
  issues: QueryIssue[];
45
121
  };
46
122
 
47
- type AnyDatabase = BaseSQLiteDatabase<"sync" | "async", any, any>;
48
123
  type ResourceAction = "list" | "read" | "create" | "update" | "delete";
49
124
  interface FieldIssue {
50
125
  /** Dotted field path; "" for the whole body (e.g. unknown keys). */
@@ -106,8 +181,14 @@ interface ResourceStoreOptions {
106
181
  email: string;
107
182
  role?: string | null;
108
183
  } | null;
109
- table: SQLiteTable;
110
- getDb: () => AnyDatabase;
184
+ /**
185
+ * The Drizzle table and database, for the Cloudflare stack. Another stack passes
186
+ * `rows` instead — a Prisma-backed one, say — and everything else is identical.
187
+ */
188
+ table?: SQLiteTable;
189
+ getDb?: () => AnyDatabase;
190
+ /** Where rows come from, when it isn't Drizzle. */
191
+ rows?: ResourceRows;
111
192
  /**
112
193
  * Called after a write succeeds, for cache invalidation. Runs before the
113
194
  * operation returns, so a caller that revalidates tags can't hand back a
@@ -124,7 +205,7 @@ interface ResourceStoreOptions {
124
205
  */
125
206
  declare function createResourceStore(options: ResourceStoreOptions): {
126
207
  resource: Resource<Record<string, Field>>;
127
- table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig>;
208
+ table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig> | undefined;
128
209
  /** `params`: page, perPage, sort, q, filter[field], cursor (as parsed by parseListQuery). */
129
210
  list(params: URLSearchParams): Promise<Result<ListResult>>;
130
211
  get(id: string): Promise<Result<Record<string, unknown>>>;
@@ -151,8 +232,11 @@ interface AuthorizeContext {
151
232
  type Authorize = (context: AuthorizeContext) => Response | void | Promise<Response | void>;
152
233
  interface ResourceHandlerOptions {
153
234
  resource: Resource;
154
- table: SQLiteTable;
155
- getDb: () => AnyDatabase;
235
+ /** Drizzle and D1, on the Cloudflare stack. Another stack passes `rows` instead. */
236
+ table?: SQLiteTable;
237
+ getDb?: () => AnyDatabase;
238
+ /** Where rows come from, when it isn't Drizzle — a Prisma-backed adapter, say. */
239
+ rows?: ResourceRows;
156
240
  authorize: Authorize;
157
241
  /** Who is making the request, for the descriptor's hooks. */
158
242
  currentUser?: ResourceStoreOptions["currentUser"];
@@ -178,7 +262,7 @@ declare function createResourceHandlers(options: ResourceHandlerOptions): {
178
262
  };
179
263
  store: {
180
264
  resource: Resource<Record<string, Field>>;
181
- table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig>;
265
+ table: SQLiteTable<drizzle_orm_sqlite_core.TableConfig> | undefined;
182
266
  list(params: URLSearchParams): Promise<Result<ListResult>>;
183
267
  get(id: string): Promise<Result<Record<string, unknown>>>;
184
268
  titles(ids: string[]): Promise<Record<string, string>>;
@@ -191,6 +275,37 @@ declare function createResourceHandlers(options: ResourceHandlerOptions): {
191
275
  };
192
276
  };
193
277
 
278
+ /**
279
+ * {@link ResourceRows} over Prisma and Postgres — the Next.js stack's half.
280
+ *
281
+ * The same nine operations the Drizzle adapter implements, expressed as Prisma queries.
282
+ * Everything a resource *means* — validation, hooks, computed values, the capped count,
283
+ * the wording of a unique-constraint error — stays in the store and is shared, so a
284
+ * descriptor behaves the same on either stack.
285
+ *
286
+ * Nothing here imports `@prisma/client`: a generated client is app-specific and this
287
+ * package can't depend on one. The delegate is described structurally instead, which is
288
+ * also what makes it easy to test without a database.
289
+ */
290
+
291
+ /**
292
+ * The part of a Prisma model delegate a resource store uses.
293
+ *
294
+ * The arguments are loose on purpose. Prisma generates a precise argument type per
295
+ * model — `Prisma.ProductFindManyArgs` and so on — and describing them here would mean
296
+ * reproducing Prisma's generics for a client this package can't import. The queries are
297
+ * all built in this file, so there is exactly one place to get them right.
298
+ */
299
+ interface PrismaDelegate {
300
+ findMany(args: any): Promise<any[]>;
301
+ findUnique(args: any): Promise<any>;
302
+ count(args: any): Promise<number>;
303
+ create(args: any): Promise<any>;
304
+ update(args: any): Promise<any>;
305
+ delete(args: any): Promise<any>;
306
+ }
307
+ declare function prismaRows(delegate: PrismaDelegate, client: unknown): ResourceRows;
308
+
194
309
  /**
195
310
  * An OpenAPI 3.1 document for an app's generated REST API, built at request time
196
311
  * from the same descriptors and policies the API itself runs on, so it can't drift.
@@ -218,4 +333,4 @@ interface OpenApiOptions {
218
333
  declare function fieldJsonSchema(def: StoredField): Schema;
219
334
  declare function openApiDocument(options: OpenApiOptions): Schema;
220
335
 
221
- export { type AnyDatabase, type Authorize, type AuthorizeContext, type ChangeEvent, type Failure, type FieldIssue, type ListQuery, type ListResult, type OpenApiOptions, type QueryIssue, type ResourceAction, type ResourceHandlerOptions, type ResourceStore, type ResourceStoreOptions, type Result, createResourceHandlers, createResourceStore, fieldJsonSchema, isFilterable, isSearchable, isSortable, openApiDocument, parseListQuery };
336
+ export { type AnyDatabase, type Authorize, type AuthorizeContext, type ChangeEvent, type ConstraintHit, type Failure, type FieldIssue, type ListQuery, type ListResult, type OpenApiOptions, type PrismaDelegate, type QueryIssue, type ResourceAction, type ResourceHandlerOptions, type ResourceRows, type ResourceStore, type ResourceStoreOptions, type Result, type Row, type RowsQuery, createResourceHandlers, createResourceStore, drizzleRows, fieldJsonSchema, isFilterable, isSearchable, isSortable, openApiDocument, parseListQuery, prismaRows };
package/dist/server.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import {
2
2
  can,
3
+ columnName,
3
4
  createValidators,
4
5
  storedFields
5
6
  } from "./chunk-VLHPSNQN.js";
6
7
 
7
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/entity.js
8
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/entity.js
8
9
  var entityKind = /* @__PURE__ */ Symbol.for("drizzle:entityKind");
9
10
  function is(value, type) {
10
11
  if (!value || typeof value !== "object") {
@@ -30,7 +31,7 @@ function is(value, type) {
30
31
  return false;
31
32
  }
32
33
 
33
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/column.js
34
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/column.js
34
35
  var Column = class {
35
36
  constructor(table, config) {
36
37
  this.table = table;
@@ -81,7 +82,7 @@ var Column = class {
81
82
  }
82
83
  };
83
84
 
84
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/column-builder.js
85
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/column-builder.js
85
86
  var ColumnBuilder = class {
86
87
  static [entityKind] = "ColumnBuilder";
87
88
  config;
@@ -184,10 +185,10 @@ var ColumnBuilder = class {
184
185
  }
185
186
  };
186
187
 
187
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/table.utils.js
188
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/table.utils.js
188
189
  var TableName = /* @__PURE__ */ Symbol.for("drizzle:Name");
189
190
 
190
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/pg-core/foreign-keys.js
191
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/foreign-keys.js
191
192
  var ForeignKeyBuilder = class {
192
193
  static [entityKind] = "PgForeignKeyBuilder";
193
194
  /** @internal */
@@ -244,12 +245,12 @@ var ForeignKey = class {
244
245
  }
245
246
  };
246
247
 
247
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/tracing-utils.js
248
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/tracing-utils.js
248
249
  function iife(fn, ...args) {
249
250
  return fn(...args);
250
251
  }
251
252
 
252
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/pg-core/unique-constraint.js
253
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/unique-constraint.js
253
254
  function uniqueKeyName(table, columns) {
254
255
  return `${table[TableName]}_${columns.join("_")}_unique`;
255
256
  }
@@ -299,7 +300,7 @@ var UniqueConstraint = class {
299
300
  }
300
301
  };
301
302
 
302
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/pg-core/utils/array.js
303
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/utils/array.js
303
304
  function parsePgArrayValue(arrayString, startFrom, inQuotes) {
304
305
  for (let i = startFrom; i < arrayString.length; i++) {
305
306
  const char = arrayString[i];
@@ -375,7 +376,7 @@ function makePgArray(array) {
375
376
  }).join(",")}}`;
376
377
  }
377
378
 
378
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/pg-core/columns/common.js
379
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/columns/common.js
379
380
  var PgColumnBuilder = class extends ColumnBuilder {
380
381
  foreignKeyConfigs = [];
381
382
  static [entityKind] = "PgColumnBuilder";
@@ -559,7 +560,7 @@ var PgArray = class _PgArray extends PgColumn {
559
560
  }
560
561
  };
561
562
 
562
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/pg-core/columns/enum.js
563
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/pg-core/columns/enum.js
563
564
  var PgEnumObjectColumnBuilder = class extends PgColumnBuilder {
564
565
  static [entityKind] = "PgEnumObjectColumnBuilder";
565
566
  constructor(name, enumInstance) {
@@ -617,7 +618,7 @@ var PgEnumColumn = class extends PgColumn {
617
618
  }
618
619
  };
619
620
 
620
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/subquery.js
621
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/subquery.js
621
622
  var Subquery = class {
622
623
  static [entityKind] = "Subquery";
623
624
  constructor(sql2, fields, alias, isWith = false, usedTables = []) {
@@ -638,10 +639,10 @@ var WithSubquery = class extends Subquery {
638
639
  static [entityKind] = "WithSubquery";
639
640
  };
640
641
 
641
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/version.js
642
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/version.js
642
643
  var version = "0.45.2";
643
644
 
644
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/tracing.js
645
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/tracing.js
645
646
  var otel;
646
647
  var rawTracer;
647
648
  var tracer = {
@@ -676,10 +677,10 @@ var tracer = {
676
677
  }
677
678
  };
678
679
 
679
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/view-common.js
680
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/view-common.js
680
681
  var ViewBaseConfig = /* @__PURE__ */ Symbol.for("drizzle:ViewBaseConfig");
681
682
 
682
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/table.js
683
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/table.js
683
684
  var Schema = /* @__PURE__ */ Symbol.for("drizzle:Schema");
684
685
  var Columns = /* @__PURE__ */ Symbol.for("drizzle:Columns");
685
686
  var ExtraConfigColumns = /* @__PURE__ */ Symbol.for("drizzle:ExtraConfigColumns");
@@ -735,7 +736,7 @@ var Table = class {
735
736
  }
736
737
  };
737
738
 
738
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/sql/sql.js
739
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/sql.js
739
740
  var FakePrimitiveParam = class {
740
741
  static [entityKind] = "FakePrimitiveParam";
741
742
  };
@@ -847,13 +848,13 @@ var SQL = class _SQL {
847
848
  };
848
849
  }
849
850
  if (is(chunk, Column)) {
850
- const columnName = casing.getColumnCasing(chunk);
851
+ const columnName2 = casing.getColumnCasing(chunk);
851
852
  if (_config.invokeSource === "indexes") {
852
- return { sql: escapeName(columnName), params: [] };
853
+ return { sql: escapeName(columnName2), params: [] };
853
854
  }
854
855
  const schemaName = chunk.table[Table.Symbol.Schema];
855
856
  return {
856
- sql: chunk.table[IsAlias] || schemaName === void 0 ? escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName) : escapeName(schemaName) + "." + escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName),
857
+ sql: chunk.table[IsAlias] || schemaName === void 0 ? escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName2) : escapeName(schemaName) + "." + escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName2),
857
858
  params: []
858
859
  };
859
860
  }
@@ -1112,13 +1113,13 @@ Subquery.prototype.getSQL = function() {
1112
1113
  return new SQL([this]);
1113
1114
  };
1114
1115
 
1115
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/utils.js
1116
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/utils.js
1116
1117
  function getTableColumns(table) {
1117
1118
  return table[Table.Symbol.Columns];
1118
1119
  }
1119
1120
  var textDecoder = typeof TextDecoder === "undefined" ? null : new TextDecoder();
1120
1121
 
1121
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/sql/expressions/conditions.js
1122
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/expressions/conditions.js
1122
1123
  function bindIfParam(value, column) {
1123
1124
  if (isDriverValueEncoder(column) && !isSQLWrapper(value) && !is(value, Param) && !is(value, Placeholder) && !is(value, Column) && !is(value, Table) && !is(value, View)) {
1124
1125
  return new Param(value, column);
@@ -1173,7 +1174,7 @@ function isNull(value) {
1173
1174
  return sql`${value} is null`;
1174
1175
  }
1175
1176
 
1176
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/sql/expressions/select.js
1177
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/expressions/select.js
1177
1178
  function asc(column) {
1178
1179
  return sql`${column} asc`;
1179
1180
  }
@@ -1181,11 +1182,101 @@ function desc(column) {
1181
1182
  return sql`${column} desc`;
1182
1183
  }
1183
1184
 
1184
- // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_b372b29e6d5511672c7f9f9d2ac40572/node_modules/drizzle-orm/sql/functions/aggregate.js
1185
+ // ../../node_modules/.pnpm/drizzle-orm@0.45.2_@cloudfl_21866ab18c10d2d988b916e06105fbce/node_modules/drizzle-orm/sql/functions/aggregate.js
1185
1186
  function count(expression) {
1186
1187
  return sql`count(${expression || sql.raw("*")})`.mapWith(Number);
1187
1188
  }
1188
1189
 
1190
+ // src/server/drizzle-rows.ts
1191
+ function errorText(error) {
1192
+ const parts = [];
1193
+ for (let current = error, depth = 0; current && depth < 5; depth++) {
1194
+ if (current instanceof Error) {
1195
+ parts.push(current.message);
1196
+ current = current.cause;
1197
+ } else {
1198
+ parts.push(String(current));
1199
+ break;
1200
+ }
1201
+ }
1202
+ return parts.join(" | ");
1203
+ }
1204
+ function drizzleRows(table, getDb) {
1205
+ const columns = getTableColumns(table);
1206
+ const idColumn = columns.id;
1207
+ const byId = (id) => eq(idColumn, id);
1208
+ function matching(query) {
1209
+ const conditions = [];
1210
+ if (query.search && query.search.fields.length > 0) {
1211
+ const pattern = `%${query.search.term.replace(/[\\%_]/g, (char) => `\\${char}`)}%`;
1212
+ const searchable = query.search.fields.map((key) => columns[key]);
1213
+ conditions.push(or(...searchable.map((column) => sql`${column} LIKE ${pattern} ESCAPE '\\'`)));
1214
+ }
1215
+ for (const [key, value] of Object.entries(query.filters)) {
1216
+ conditions.push(value === null ? isNull(columns[key]) : eq(columns[key], value));
1217
+ }
1218
+ return conditions;
1219
+ }
1220
+ return {
1221
+ columns,
1222
+ get db() {
1223
+ return getDb();
1224
+ },
1225
+ async find(query) {
1226
+ const conditions = matching(query);
1227
+ const sortColumn = columns[query.sort.field];
1228
+ const descending = query.sort.direction === "desc";
1229
+ const order = descending ? [desc(sortColumn), desc(idColumn)] : [asc(sortColumn), asc(idColumn)];
1230
+ if (query.cursor) {
1231
+ const { value, id, greaterThan } = query.cursor;
1232
+ conditions.push(
1233
+ greaterThan ? or(sql`${sortColumn} > ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} > ${id}`)) : or(sql`${sortColumn} < ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} < ${id}`))
1234
+ );
1235
+ }
1236
+ const where = conditions.length ? and(...conditions) : void 0;
1237
+ const statement = getDb().select().from(table).where(where).orderBy(...order).limit(query.limit);
1238
+ const rows = query.offset ? await statement.offset(query.offset) : await statement;
1239
+ return rows;
1240
+ },
1241
+ async countUpTo(query, limit) {
1242
+ const conditions = matching(query);
1243
+ const where = conditions.length ? and(...conditions) : void 0;
1244
+ const db = getDb();
1245
+ const [counted] = await db.select({ total: count() }).from(db.select({ id: idColumn }).from(table).where(where).limit(limit).as("capped"));
1246
+ return counted?.total ?? 0;
1247
+ },
1248
+ async byId(id) {
1249
+ const [record] = await getDb().select().from(table).where(byId(id)).limit(1);
1250
+ return record ?? null;
1251
+ },
1252
+ async titles(ids, titleField) {
1253
+ const titleColumn = columns[titleField] ?? idColumn;
1254
+ const rows = await getDb().select({ id: idColumn, title: titleColumn }).from(table).where(inArray(idColumn, ids));
1255
+ return rows;
1256
+ },
1257
+ async insert(values) {
1258
+ const [record] = await getDb().insert(table).values(values).returning();
1259
+ return record;
1260
+ },
1261
+ async update(id, values) {
1262
+ const [record] = await getDb().update(table).set(values).where(byId(id)).returning();
1263
+ return record ?? null;
1264
+ },
1265
+ async remove(id) {
1266
+ const deleted = await getDb().delete(table).where(byId(id)).returning({ id: idColumn });
1267
+ return deleted.length > 0;
1268
+ },
1269
+ constraint(error) {
1270
+ const text = errorText(error);
1271
+ const unique = /UNIQUE constraint failed: ([\w.]+(?:, [\w.]+)*)/.exec(text);
1272
+ if (unique) return { kind: "unique", column: unique[1].split(", ")[0].split(".").pop() };
1273
+ if (/FOREIGN KEY constraint failed/.test(text)) return { kind: "foreignKey" };
1274
+ if (/CHECK constraint failed/.test(text)) return { kind: "check" };
1275
+ return void 0;
1276
+ }
1277
+ };
1278
+ }
1279
+
1189
1280
  // src/server/query.ts
1190
1281
  function encodeCursor(cursor) {
1191
1282
  const json2 = JSON.stringify([cursor.value, cursor.id, cursor.direction === "before" ? 0 : 1]);
@@ -1284,45 +1375,36 @@ function toCursorValue(value) {
1284
1375
  if (typeof value === "object") return String(value);
1285
1376
  return value;
1286
1377
  }
1287
- function errorText(error) {
1288
- const parts = [];
1289
- for (let current = error, depth = 0; current && depth < 5; depth++) {
1290
- if (current instanceof Error) {
1291
- parts.push(current.message);
1292
- current = current.cause;
1293
- } else {
1294
- parts.push(String(current));
1295
- break;
1296
- }
1297
- }
1298
- return parts.join(" | ");
1299
- }
1300
1378
  function createResourceStore(options) {
1301
- const { resource, table, getDb } = options;
1379
+ const { resource, table } = options;
1302
1380
  const validators = createValidators(resource);
1303
- const columns = getTableColumns(table);
1304
1381
  const fields = storedFields(resource);
1305
- for (const key of ["id", "createdAt", "updatedAt", ...fields.map(([key2]) => key2)]) {
1306
- if (!columns[key]) {
1307
- throw new Error(`Resource "${resource.name}": table has no column for "${key}". Run \`flare sync-types\` and create a migration.`);
1382
+ if (!options.rows && !(table && options.getDb)) {
1383
+ throw new Error(`Resource "${resource.name}": a store needs either a Drizzle table and getDb, or rows.`);
1384
+ }
1385
+ const rows = options.rows ?? drizzleRows(table, options.getDb);
1386
+ const columns = "columns" in rows ? rows.columns : void 0;
1387
+ if (columns) {
1388
+ for (const key of ["id", "createdAt", "updatedAt", ...fields.map(([key2]) => key2)]) {
1389
+ if (!columns[key]) {
1390
+ throw new Error(`Resource "${resource.name}": table has no column for "${key}". Run \`flare sync-types\` and create a migration.`);
1391
+ }
1308
1392
  }
1309
1393
  }
1310
- const idColumn = columns.id;
1311
- const columnKeyByName = new Map(Object.entries(columns).map(([key, column]) => [column.name, key]));
1394
+ const keyForColumn = (name) => columns ? Object.entries(columns).find(([, column]) => column.name === name)?.[0] : ["id", "createdAt", "updatedAt", ...fields.map(([key]) => key)].find((key) => columnName(key) === name || key === name);
1312
1395
  const fail = (status, error, extra = {}) => ({ ok: false, status, error, ...extra });
1313
1396
  function constraintFailure(error, action) {
1314
- const text = errorText(error);
1315
- const unique = /UNIQUE constraint failed: ([\w.]+(?:, [\w.]+)*)/.exec(text);
1316
- if (unique) {
1317
- const key = columnKeyByName.get(unique[1].split(", ")[0].split(".").pop());
1397
+ const hit = rows.constraint(error);
1398
+ if (!hit) return void 0;
1399
+ if (hit.kind === "unique") {
1400
+ const key = hit.column ? keyForColumn(hit.column) : void 0;
1318
1401
  const label = key ? resource.fields[key]?.label ?? key : "Value";
1319
1402
  return fail(409, `${label} is already taken.`, key ? { field: key } : {});
1320
1403
  }
1321
- if (/FOREIGN KEY constraint failed/.test(text)) {
1404
+ if (hit.kind === "foreignKey") {
1322
1405
  return action === "delete" ? fail(409, `This ${resource.label.toLowerCase()} is still referenced by other records.`) : fail(422, "A related record doesn't exist.");
1323
1406
  }
1324
- if (/CHECK constraint failed/.test(text)) return fail(422, "A value is outside its allowed options.");
1325
- return void 0;
1407
+ return fail(422, "A value is outside its allowed options.");
1326
1408
  }
1327
1409
  async function guarded(action, work) {
1328
1410
  try {
@@ -1347,7 +1429,6 @@ function createResourceStore(options) {
1347
1429
  return result;
1348
1430
  }
1349
1431
  const invalid = (issues) => fail(422, "Validation failed.", { issues: issues.map((issue) => ({ path: issue.path.map(String).join("."), message: issue.message })) });
1350
- const byId = (id) => eq(idColumn, id);
1351
1432
  const notFound = () => fail(404, `${resource.label} not found.`);
1352
1433
  const computed = Object.entries(resource.computed ?? {});
1353
1434
  const withComputed = (row) => {
@@ -1363,7 +1444,7 @@ function createResourceStore(options) {
1363
1444
  return result;
1364
1445
  };
1365
1446
  const hooks = resource.hooks ?? {};
1366
- const hookContext = async () => ({ db: getDb(), user: await options.currentUser?.() ?? null });
1447
+ const hookContext = async () => ({ db: rows.db, user: await options.currentUser?.() ?? null });
1367
1448
  return {
1368
1449
  resource,
1369
1450
  table,
@@ -1372,50 +1453,35 @@ function createResourceStore(options) {
1372
1453
  const parsed = parseListQuery(resource, params);
1373
1454
  if ("issues" in parsed) return fail(400, "Invalid query.", { queryIssues: parsed.issues });
1374
1455
  const { page, perPage, sort, q, filters, cursor } = parsed.query;
1375
- const conditions = [];
1376
- if (q) {
1377
- const pattern = `%${q.replace(/[\\%_]/g, (char) => `\\${char}`)}%`;
1378
- const searchable = fields.filter(([, def]) => isSearchable(def)).map(([key]) => columns[key]);
1379
- if (searchable.length) conditions.push(or(...searchable.map((column) => sql`${column} LIKE ${pattern} ESCAPE '\\'`)));
1380
- }
1381
- for (const [key, value] of Object.entries(filters)) {
1382
- conditions.push(value === null ? isNull(columns[key]) : eq(columns[key], value));
1383
- }
1384
- const filterWhere = conditions.length ? and(...conditions) : void 0;
1385
- const sortColumn = columns[sort.field];
1456
+ const searchable = fields.filter(([, def]) => isSearchable(def)).map(([key]) => key);
1457
+ const matching = { search: q ? { term: q, fields: searchable } : void 0, filters };
1386
1458
  const backwards = cursor?.direction === "before";
1387
1459
  const descending = backwards ? sort.direction === "asc" : sort.direction === "desc";
1388
- const order = descending ? [desc(sortColumn), desc(idColumn)] : [asc(sortColumn), asc(idColumn)];
1389
- const pageConditions = [...conditions];
1390
- if (cursor) {
1391
- const value = cursor.value;
1392
- pageConditions.push(
1393
- descending ? or(sql`${sortColumn} < ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} < ${cursor.id}`)) : or(sql`${sortColumn} > ${value}`, and(sql`${sortColumn} = ${value}`, sql`${idColumn} > ${cursor.id}`))
1394
- );
1395
- }
1396
- const where = pageConditions.length ? and(...pageConditions) : void 0;
1397
- const db = getDb();
1398
- const query = db.select().from(table).where(where).orderBy(...order).limit(perPage + 1);
1399
- const [found, counted] = await Promise.all([
1400
- cursor ? query : query.offset((page - 1) * perPage),
1460
+ const [found, counting] = await Promise.all([
1401
1461
  // One row past the limit is enough to know there's more without counting it all.
1402
- db.select({ total: count() }).from(db.select({ id: idColumn }).from(table).where(filterWhere).limit(COUNT_LIMIT + 1).as("capped"))
1462
+ rows.find({
1463
+ ...matching,
1464
+ sort: { field: sort.field, direction: descending ? "desc" : "asc" },
1465
+ cursor: cursor ? { field: sort.field, value: cursor.value, id: cursor.id, greaterThan: !descending } : void 0,
1466
+ limit: perPage + 1,
1467
+ offset: cursor ? void 0 : (page - 1) * perPage
1468
+ }),
1469
+ rows.countUpTo(matching, COUNT_LIMIT + 1)
1403
1470
  ]);
1404
1471
  const hasMore = found.length > perPage;
1405
- const rows = (hasMore ? found.slice(0, perPage) : found).map(withComputed);
1406
- if (backwards) rows.reverse();
1407
- const counting = counted[0]?.total ?? 0;
1472
+ const page_ = (hasMore ? found.slice(0, perPage) : found).map(withComputed);
1473
+ if (backwards) page_.reverse();
1408
1474
  const exactTotal = counting <= COUNT_LIMIT;
1409
1475
  const total = exactTotal ? counting : COUNT_LIMIT;
1410
- const first = rows[0];
1411
- const last = rows[rows.length - 1];
1476
+ const first = page_[0];
1477
+ const last = page_[page_.length - 1];
1412
1478
  const moreAfter = backwards ? true : hasMore;
1413
1479
  const moreBefore = backwards ? hasMore : Boolean(cursor) || page > 1;
1414
1480
  const cursorFor = (row, direction) => row ? encodeCursor({ value: toCursorValue(row[sort.field]), id: String(row.id), direction }) : void 0;
1415
1481
  return {
1416
1482
  ok: true,
1417
1483
  data: {
1418
- data: rows,
1484
+ data: page_,
1419
1485
  meta: {
1420
1486
  page,
1421
1487
  perPage,
@@ -1429,16 +1495,15 @@ function createResourceStore(options) {
1429
1495
  };
1430
1496
  },
1431
1497
  async get(id) {
1432
- const [record] = await getDb().select().from(table).where(byId(id)).limit(1);
1498
+ const record = await rows.byId(id);
1433
1499
  return record ? { ok: true, data: withComputed(record) } : notFound();
1434
1500
  },
1435
1501
  /** Title-field values for a set of ids (for showing relations). Missing ids are omitted. */
1436
1502
  async titles(ids) {
1437
1503
  const unique = [...new Set(ids.filter(Boolean))];
1438
1504
  if (unique.length === 0) return {};
1439
- const titleColumn = columns[resource.titleField] ?? idColumn;
1440
- const rows = await getDb().select({ id: idColumn, title: titleColumn }).from(table).where(inArray(idColumn, unique));
1441
- return Object.fromEntries(rows.map((row) => [row.id, row.title == null ? row.id : String(row.title)]));
1505
+ const found = await rows.titles(unique, resource.titleField);
1506
+ return Object.fromEntries(found.map((row) => [row.id, row.title == null ? row.id : String(row.title)]));
1442
1507
  },
1443
1508
  create(raw) {
1444
1509
  return writing("create", async () => {
@@ -1448,7 +1513,7 @@ function createResourceStore(options) {
1448
1513
  if (!result.success) return invalid(result.error.issues);
1449
1514
  const input = result.data;
1450
1515
  const now = /* @__PURE__ */ new Date();
1451
- const [record] = await getDb().insert(table).values({ ...input, id: crypto.randomUUID(), createdAt: now, updatedAt: now }).returning();
1516
+ const record = await rows.insert({ ...input, id: crypto.randomUUID(), createdAt: now, updatedAt: now });
1452
1517
  const saved = withComputed(record);
1453
1518
  await hooks.afterCreate?.(saved, context);
1454
1519
  return { ok: true, data: saved };
@@ -1458,13 +1523,12 @@ function createResourceStore(options) {
1458
1523
  update(id, raw) {
1459
1524
  return writing("update", async () => {
1460
1525
  const context = await hookContext();
1461
- const [existing] = hooks.beforeUpdate || hooks.afterUpdate ? await getDb().select().from(table).where(byId(id)).limit(1) : [];
1462
- const current = existing ?? null;
1526
+ const current = hooks.beforeUpdate || hooks.afterUpdate ? await rows.byId(id) : null;
1463
1527
  const supplied = hooks.beforeUpdate ? await hooks.beforeUpdate({ ...raw ?? {} }, { ...context, id, current }) : raw;
1464
1528
  const result = validators.update.safeParse(supplied);
1465
1529
  if (!result.success) return invalid(result.error.issues);
1466
1530
  const input = result.data;
1467
- const [record] = await getDb().update(table).set({ ...input, updatedAt: /* @__PURE__ */ new Date() }).where(byId(id)).returning();
1531
+ const record = await rows.update(id, { ...input, updatedAt: /* @__PURE__ */ new Date() });
1468
1532
  if (!record) return notFound();
1469
1533
  const saved = withComputed(record);
1470
1534
  await hooks.afterUpdate?.(saved, { ...context, previous: current });
@@ -1481,7 +1545,7 @@ function createResourceStore(options) {
1481
1545
  values[key] = "default" in def && def.default !== void 0 ? def.default : def.required ? void 0 : null;
1482
1546
  }
1483
1547
  Object.assign(values, result.data, { updatedAt: /* @__PURE__ */ new Date() });
1484
- const [record] = await getDb().update(table).set(values).where(byId(id)).returning();
1548
+ const record = await rows.update(id, values);
1485
1549
  return record ? { ok: true, data: withComputed(record) } : notFound();
1486
1550
  });
1487
1551
  },
@@ -1489,11 +1553,9 @@ function createResourceStore(options) {
1489
1553
  return writing("delete", async () => {
1490
1554
  const context = await hookContext();
1491
1555
  if (hooks.beforeDelete) {
1492
- const [existing] = await getDb().select().from(table).where(byId(id)).limit(1);
1493
- await hooks.beforeDelete({ ...context, id, current: existing ?? null });
1556
+ await hooks.beforeDelete({ ...context, id, current: await rows.byId(id) });
1494
1557
  }
1495
- const deleted = await getDb().delete(table).where(byId(id)).returning({ id: idColumn });
1496
- if (deleted.length === 0) return notFound();
1558
+ if (!await rows.remove(id)) return notFound();
1497
1559
  await hooks.afterDelete?.({ ...context, id });
1498
1560
  return { ok: true, data: { id } };
1499
1561
  });
@@ -1586,6 +1648,99 @@ function createResourceHandlers(options) {
1586
1648
  };
1587
1649
  }
1588
1650
 
1651
+ // src/server/prisma-rows.ts
1652
+ var NOT_FOUND = "P2025";
1653
+ var codeOf = (error) => typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
1654
+ function uniqueColumn(error) {
1655
+ const meta = error.meta;
1656
+ if (!meta) return void 0;
1657
+ const target = meta.target;
1658
+ if (Array.isArray(target) && target.length > 0) return String(target[0]);
1659
+ if (typeof target === "string") return fromIndexName(target);
1660
+ const cause = meta.driverAdapterError?.cause;
1661
+ const constraint = cause?.constraint;
1662
+ if (constraint?.fields?.length) return constraint.fields[0];
1663
+ if (constraint?.index) return fromIndexName(constraint.index);
1664
+ return void 0;
1665
+ }
1666
+ function fromIndexName(name) {
1667
+ const match = /^.*?_(.+)_key$/.exec(name);
1668
+ return match ? match[1] : name;
1669
+ }
1670
+ function prismaRows(delegate, client) {
1671
+ function matching(query) {
1672
+ const where = { ...query.filters };
1673
+ if (query.search && query.search.fields.length > 0) {
1674
+ where.OR = query.search.fields.map((field) => ({ [field]: { contains: query.search.term, mode: "insensitive" } }));
1675
+ }
1676
+ return where;
1677
+ }
1678
+ return {
1679
+ db: client,
1680
+ async find(query) {
1681
+ const where = matching(query);
1682
+ if (query.cursor) {
1683
+ const { field, value, id, greaterThan } = query.cursor;
1684
+ const op = greaterThan ? "gt" : "lt";
1685
+ const keyset = [{ [field]: { [op]: value } }, { AND: [{ [field]: value }, { id: { [op]: id } }] }];
1686
+ where.AND = [...where.AND ?? [], { OR: keyset }];
1687
+ }
1688
+ return delegate.findMany({
1689
+ where,
1690
+ orderBy: [{ [query.sort.field]: query.sort.direction }, { id: query.sort.direction }],
1691
+ take: query.limit,
1692
+ ...query.offset ? { skip: query.offset } : {}
1693
+ });
1694
+ },
1695
+ countUpTo(query, limit) {
1696
+ return delegate.count({ where: matching(query), take: limit });
1697
+ },
1698
+ byId(id) {
1699
+ return delegate.findUnique({ where: { id } });
1700
+ },
1701
+ async titles(ids, titleField) {
1702
+ const rows = await delegate.findMany({ where: { id: { in: ids } }, select: { id: true, [titleField]: true } });
1703
+ return rows.map((row) => ({ id: String(row.id), title: row[titleField] }));
1704
+ },
1705
+ insert(values) {
1706
+ return delegate.create({ data: values });
1707
+ },
1708
+ async update(id, values) {
1709
+ try {
1710
+ return await delegate.update({ where: { id }, data: values });
1711
+ } catch (error) {
1712
+ if (codeOf(error) === NOT_FOUND) return null;
1713
+ throw error;
1714
+ }
1715
+ },
1716
+ async remove(id) {
1717
+ try {
1718
+ await delegate.delete({ where: { id } });
1719
+ return true;
1720
+ } catch (error) {
1721
+ if (codeOf(error) === NOT_FOUND) return false;
1722
+ throw error;
1723
+ }
1724
+ },
1725
+ constraint(error) {
1726
+ switch (codeOf(error)) {
1727
+ case "P2002":
1728
+ return { kind: "unique", column: uniqueColumn(error) };
1729
+ case "P2003":
1730
+ case "P2014":
1731
+ return { kind: "foreignKey" };
1732
+ // A value outside its type, too long for its column, or null where it can't be.
1733
+ case "P2000":
1734
+ case "P2011":
1735
+ case "P2020":
1736
+ return { kind: "check" };
1737
+ default:
1738
+ return void 0;
1739
+ }
1740
+ }
1741
+ };
1742
+ }
1743
+
1589
1744
  // src/server/openapi.ts
1590
1745
  var E164 = "^\\+[1-9]\\d{6,14}$";
1591
1746
  function fieldJsonSchema(def) {
@@ -1859,10 +2014,12 @@ function openApiDocument(options) {
1859
2014
  export {
1860
2015
  createResourceHandlers,
1861
2016
  createResourceStore,
2017
+ drizzleRows,
1862
2018
  fieldJsonSchema,
1863
2019
  isFilterable,
1864
2020
  isSearchable,
1865
2021
  isSortable,
1866
2022
  openApiDocument,
1867
- parseListQuery
2023
+ parseListQuery,
2024
+ prismaRows
1868
2025
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flaredev/core",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Flare runtime: resource descriptors, field grammar, and Cloudflare-native helpers",
5
5
  "license": "MIT",
6
6
  "author": "Muke Johnbaptist",