@celsoft/platform 0.4.0 → 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.
Files changed (62) hide show
  1. package/dist/adapters/cloudflare.d.ts +10 -1
  2. package/dist/adapters/cloudflare.js +46 -2
  3. package/dist/adapters/cloudflare.js.map +1 -1
  4. package/dist/adapters/drizzle.d.ts +15 -0
  5. package/dist/adapters/drizzle.js +111 -0
  6. package/dist/adapters/drizzle.js.map +1 -0
  7. package/dist/adapters/github.d.ts +1 -0
  8. package/dist/adapters/github.js +4 -0
  9. package/dist/adapters/github.js.map +1 -1
  10. package/dist/adapters/neon.d.ts +2 -0
  11. package/dist/adapters/neon.js +8 -0
  12. package/dist/adapters/neon.js.map +1 -1
  13. package/dist/adapters/process.d.ts +1 -7
  14. package/dist/adapters/process.js +0 -22
  15. package/dist/adapters/process.js.map +1 -1
  16. package/dist/adapters/resend.d.ts +1 -0
  17. package/dist/adapters/resend.js +3 -0
  18. package/dist/adapters/resend.js.map +1 -1
  19. package/dist/cli.js +71 -9
  20. package/dist/cli.js.map +1 -1
  21. package/dist/config.d.ts +11 -4
  22. package/dist/config.js +26 -9
  23. package/dist/config.js.map +1 -1
  24. package/dist/fakes.d.ts +24 -4
  25. package/dist/fakes.js +58 -6
  26. package/dist/fakes.js.map +1 -1
  27. package/dist/init.js +5 -5
  28. package/dist/init.js.map +1 -1
  29. package/dist/lifecycle.d.ts +7 -0
  30. package/dist/lifecycle.js +134 -18
  31. package/dist/lifecycle.js.map +1 -1
  32. package/dist/ownership.d.ts +16 -0
  33. package/dist/ownership.js +40 -0
  34. package/dist/ownership.js.map +1 -0
  35. package/dist/ports.d.ts +18 -3
  36. package/dist/runtime/auth.d.ts +1181 -6
  37. package/dist/runtime/auth.js +44 -14
  38. package/dist/runtime/auth.js.map +1 -1
  39. package/dist/runtime/files.js +4 -1
  40. package/dist/runtime/files.js.map +1 -1
  41. package/dist/runtime/guard.d.ts +12 -0
  42. package/dist/runtime/guard.js +42 -0
  43. package/dist/runtime/guard.js.map +1 -0
  44. package/dist/runtime/index.d.ts +18 -8
  45. package/dist/runtime/index.js +67 -19
  46. package/dist/runtime/index.js.map +1 -1
  47. package/dist/runtime/owner.d.ts +12 -0
  48. package/dist/runtime/owner.js +54 -0
  49. package/dist/runtime/owner.js.map +1 -0
  50. package/dist/runtime/screens.d.ts +4 -0
  51. package/dist/runtime/screens.js +158 -0
  52. package/dist/runtime/screens.js.map +1 -0
  53. package/dist/schema.d.ts +2775 -0
  54. package/dist/schema.js +129 -0
  55. package/dist/schema.js.map +1 -0
  56. package/dist/workflow.js +15 -5
  57. package/dist/workflow.js.map +1 -1
  58. package/dist/wrangler-config.d.ts +5 -0
  59. package/dist/wrangler-config.js +11 -2
  60. package/dist/wrangler-config.js.map +1 -1
  61. package/package.json +10 -4
  62. package/schema.json +18 -14
package/dist/schema.js ADDED
@@ -0,0 +1,129 @@
1
+ import { sql } from "drizzle-orm";
2
+ import { boolean, index, integer, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
3
+ // Better Auth's tables, with its core, admin and organization fields, transcribed from
4
+ // getAuthTables() in the installed version; schema.test.ts fails when they drift apart.
5
+ // Property keys stay camelCase because the Drizzle adapter matches Better Auth's field names
6
+ // against them; column names are snake_case like the rest of an app's tables.
7
+ // Every id is a UUIDv7 filled by Postgres 18, so ids sort by creation time and are never
8
+ // supplied by code. An id is not a secret: anything unguessable gets its own token.
9
+ export const id = () => uuid("id").primaryKey().default(sql `uuidv7()`);
10
+ export const timestamps = () => ({
11
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
12
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
13
+ });
14
+ export const user = pgTable("user", {
15
+ id: id(),
16
+ name: text("name").notNull(),
17
+ email: text("email").notNull().unique(),
18
+ emailVerified: boolean("email_verified").notNull().default(false),
19
+ image: text("image"),
20
+ role: text("role"),
21
+ banned: boolean("banned").default(false),
22
+ banReason: text("ban_reason"),
23
+ banExpires: timestamp("ban_expires", { withTimezone: true }),
24
+ ...timestamps(),
25
+ });
26
+ export const session = pgTable("session", {
27
+ id: id(),
28
+ expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
29
+ token: text("token").notNull().unique(),
30
+ ipAddress: text("ip_address"),
31
+ userAgent: text("user_agent"),
32
+ userId: uuid("user_id")
33
+ .notNull()
34
+ .references(() => user.id, { onDelete: "cascade" }),
35
+ impersonatedBy: uuid("impersonated_by"),
36
+ activeOrganizationId: uuid("active_organization_id"),
37
+ activeTeamId: uuid("active_team_id"),
38
+ ...timestamps(),
39
+ }, (t) => [index("session_user_id_idx").on(t.userId)]);
40
+ export const account = pgTable("account", {
41
+ id: id(),
42
+ accountId: text("account_id").notNull(),
43
+ providerId: text("provider_id").notNull(),
44
+ userId: uuid("user_id")
45
+ .notNull()
46
+ .references(() => user.id, { onDelete: "cascade" }),
47
+ accessToken: text("access_token"),
48
+ refreshToken: text("refresh_token"),
49
+ idToken: text("id_token"),
50
+ accessTokenExpiresAt: timestamp("access_token_expires_at", { withTimezone: true }),
51
+ refreshTokenExpiresAt: timestamp("refresh_token_expires_at", { withTimezone: true }),
52
+ scope: text("scope"),
53
+ password: text("password"),
54
+ ...timestamps(),
55
+ }, (t) => [index("account_user_id_idx").on(t.userId)]);
56
+ export const verification = pgTable("verification", {
57
+ id: id(),
58
+ identifier: text("identifier").notNull(),
59
+ value: text("value").notNull(),
60
+ expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
61
+ ...timestamps(),
62
+ }, (t) => [index("verification_identifier_idx").on(t.identifier)]);
63
+ // Organization tables exist whenever auth is on, so turning organizations off and on again
64
+ // only hides and restores routes; no migration ever drops their data.
65
+ export const organization = pgTable("organization", {
66
+ id: id(),
67
+ name: text("name").notNull(),
68
+ slug: text("slug").notNull().unique(),
69
+ logo: text("logo"),
70
+ metadata: text("metadata"),
71
+ ...timestamps(),
72
+ });
73
+ export const member = pgTable("member", {
74
+ id: id(),
75
+ organizationId: uuid("organization_id")
76
+ .notNull()
77
+ .references(() => organization.id, { onDelete: "cascade" }),
78
+ userId: uuid("user_id")
79
+ .notNull()
80
+ .references(() => user.id, { onDelete: "cascade" }),
81
+ role: text("role").notNull().default("member"),
82
+ ...timestamps(),
83
+ }, (t) => [index("member_organization_id_idx").on(t.organizationId), index("member_user_id_idx").on(t.userId)]);
84
+ export const invitation = pgTable("invitation", {
85
+ id: id(),
86
+ organizationId: uuid("organization_id")
87
+ .notNull()
88
+ .references(() => organization.id, { onDelete: "cascade" }),
89
+ email: text("email").notNull(),
90
+ role: text("role"),
91
+ teamId: uuid("team_id"),
92
+ status: text("status").notNull().default("pending"),
93
+ expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
94
+ inviterId: uuid("inviter_id")
95
+ .notNull()
96
+ .references(() => user.id, { onDelete: "cascade" }),
97
+ ...timestamps(),
98
+ }, (t) => [index("invitation_organization_id_idx").on(t.organizationId), index("invitation_email_idx").on(t.email)]);
99
+ export const team = pgTable("team", {
100
+ id: id(),
101
+ name: text("name").notNull(),
102
+ memberCount: integer("member_count").notNull().default(0),
103
+ organizationId: uuid("organization_id")
104
+ .notNull()
105
+ .references(() => organization.id, { onDelete: "cascade" }),
106
+ ...timestamps(),
107
+ }, (t) => [index("team_organization_id_idx").on(t.organizationId)]);
108
+ export const teamMember = pgTable("team_member", {
109
+ id: id(),
110
+ teamId: uuid("team_id")
111
+ .notNull()
112
+ .references(() => team.id, { onDelete: "cascade" }),
113
+ userId: uuid("user_id")
114
+ .notNull()
115
+ .references(() => user.id, { onDelete: "cascade" }),
116
+ membershipKey: text("membership_key").unique(),
117
+ ...timestamps(),
118
+ }, (t) => [index("team_member_team_id_idx").on(t.teamId), index("team_member_user_id_idx").on(t.userId)]);
119
+ // The owner's one-time recovery code, stored hashed; using it deletes the row, and the next
120
+ // sign-in issues a fresh one.
121
+ export const ownerRecovery = pgTable("owner_recovery", {
122
+ userId: uuid("user_id")
123
+ .primaryKey()
124
+ .references(() => user.id, { onDelete: "cascade" }),
125
+ codeHash: text("code_hash").notNull(),
126
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
127
+ });
128
+ export const authSchema = { user, session, account, verification, organization, member, invitation, team, teamMember };
129
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/workflow.js CHANGED
@@ -19,11 +19,17 @@ on:
19
19
  push:
20
20
  branches: [main]
21
21
  pull_request:
22
- types: [opened, synchronize, reopened, closed]
22
+ types: [opened, synchronize, reopened]
23
+ # GitHub can skip a pull_request run for a close; pull_request_target needs no merge commit, so it always runs.
24
+ pull_request_target: # zizmor: ignore[dangerous-triggers] the job runs only for this repo's own pull requests
25
+ types: [closed]
26
+ # Once a day, remove any preview whose pull request is closed but was never cleaned up.
27
+ schedule:
28
+ - cron: "17 6 * * *"
23
29
 
24
30
  concurrency:
25
- group: platform-\${{ github.event.pull_request.number || github.ref }}
26
- cancel-in-progress: \${{ github.event_name == 'pull_request' }}
31
+ group: platform-\${{ github.event.pull_request.number || (github.event_name == 'schedule' && 'sweep') || github.ref }}
32
+ cancel-in-progress: \${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
27
33
 
28
34
  permissions:
29
35
  contents: read
@@ -31,11 +37,15 @@ permissions:
31
37
 
32
38
  jobs:
33
39
  platform:
34
- if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
40
+ if: github.event_name == 'push' || github.event_name == 'schedule' || github.event.pull_request.head.repo.full_name == github.repository
35
41
  runs-on: ubuntu-latest
36
42
  environment: \${{ github.event_name == 'push' && 'production' || 'preview' }}
37
43
  steps:
38
- - uses: actions/checkout@v5${setupPnpm}
44
+ # A close cleans up with the pull request's own last commit, which knows everything its preview made.
45
+ - uses: actions/checkout@v5
46
+ with:
47
+ ref: \${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || '' }}
48
+ persist-credentials: false${setupPnpm}
39
49
  - uses: actions/setup-node@v5
40
50
  with:
41
51
  node-version: 24
@@ -1 +1 @@
1
- {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,gCAAgC,CAAC;AAW9D,2FAA2F;AAC3F,4FAA4F;AAC5F,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAiB;IAC1F,MAAM,OAAO,GAAG,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxF,MAAM,IAAI,GAAG,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,8BAA8B,CAAC;IAClG,MAAM,SAAS,GAAG,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,MAAM,gBAAgB,GAAG,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gCAAgC,MAAM,EAAE,CAAC;IACxF,MAAM,GAAG,GAAG;QACV,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,kBAAkB,IAAI,KAAK,CAAC;QACjF,kHAAkH;QAClH,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,kBAAkB,IAAI,KAAK,CAAC;QACnF,mCAAmC;KACpC,CAAC;IAEF,OAAO;;;;;;;;;;;;;;;;;;;;;;;mCAuB0B,SAAS;;;;mBAIzB,cAAc;eAClB,OAAO;eACP,IAAI,GAAG,gBAAgB;;EAEpC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CAClD,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"workflow.js","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,gCAAgC,CAAC;AAW9D,2FAA2F;AAC3F,4FAA4F;AAC5F,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAiB;IAC1F,MAAM,OAAO,GAAG,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACxF,MAAM,IAAI,GAAG,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,8BAA8B,CAAC;IAClG,MAAM,SAAS,GAAG,cAAc,KAAK,MAAM,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,MAAM,gBAAgB,GAAG,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gCAAgC,MAAM,EAAE,CAAC;IACxF,MAAM,GAAG,GAAG;QACV,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,kBAAkB,IAAI,KAAK,CAAC;QACjF,kHAAkH;QAClH,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,kBAAkB,IAAI,KAAK,CAAC;QACnF,mCAAmC;KACpC,CAAC;IAEF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCAiC6B,SAAS;;;;mBAI5B,cAAc;eAClB,OAAO;eACP,IAAI,GAAG,gBAAgB;;EAEpC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;CAClD,CAAC;AACF,CAAC"}
@@ -8,4 +8,9 @@ export interface WranglerInput {
8
8
  vars: Record<string, string>;
9
9
  bucket?: string | undefined;
10
10
  }
11
+ export declare const AUTH_LIMIT: {
12
+ readonly limit: 10;
13
+ readonly period: 60;
14
+ };
11
15
  export declare function wranglerConfig({ config, worker, hostname, accountId, hyperdriveId, vars, bucket }: WranglerInput): object;
16
+ export declare function namespaceId(worker: string): string;
@@ -1,4 +1,8 @@
1
+ import { createHash } from "node:crypto";
2
+ import { SCREEN_PATHS } from "./runtime/screens.js";
3
+ export const AUTH_LIMIT = { limit: 10, period: 60 };
1
4
  export function wranglerConfig({ config, worker, hostname, accountId, hyperdriveId, vars, bucket }) {
5
+ const auth = config.auth;
2
6
  return {
3
7
  name: worker,
4
8
  account_id: accountId,
@@ -8,12 +12,17 @@ export function wranglerConfig({ config, worker, hostname, accountId, hyperdrive
8
12
  workers_dev: false,
9
13
  routes: [{ pattern: hostname, custom_domain: true }],
10
14
  observability: { enabled: true },
11
- vars,
15
+ vars: { ...vars, APP_NAME: config.name, ...(auth && { AUTH_ORGANIZATIONS: auth.organizations ? "on" : "off" }) },
12
16
  ...(config.frontend && {
13
- assets: { directory: config.frontend, not_found_handling: "single-page-application", run_worker_first: ["/api/*"] },
17
+ assets: { directory: config.frontend, not_found_handling: "single-page-application", run_worker_first: ["/api/*", ...(auth ? SCREEN_PATHS : [])] },
14
18
  }),
15
19
  ...(hyperdriveId && { hyperdrive: [{ binding: "DB", id: hyperdriveId }] }),
16
20
  ...(bucket && { r2_buckets: [{ binding: "FILES", bucket_name: bucket }] }),
21
+ ...(auth && { ratelimits: [{ name: "AUTH_LIMIT", namespace_id: namespaceId(worker), simple: AUTH_LIMIT }] }),
17
22
  };
18
23
  }
24
+ // Rate limit namespaces are account-wide integers, so each Worker gets its own from its name.
25
+ export function namespaceId(worker) {
26
+ return String(1000 + (createHash("sha256").update(worker).digest().readUInt32BE(0) % 2_000_000_000));
27
+ }
19
28
  //# sourceMappingURL=wrangler-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrangler-config.js","sourceRoot":"","sources":["../src/wrangler-config.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAiB;IAC/G,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE,MAAM,CAAC,MAAM;QACnB,kBAAkB,EAAE,MAAM,CAAC,iBAAiB;QAC5C,mBAAmB,EAAE,CAAC,eAAe,CAAC;QACtC,WAAW,EAAE,KAAK;QAClB,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;QACpD,aAAa,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;QAChC,IAAI;QACJ,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI;YACrB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,CAAC,QAAQ,CAAC,EAAE;SACpH,CAAC;QACF,GAAG,CAAC,YAAY,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,MAAM,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;KAC3E,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"wrangler-config.js","sourceRoot":"","sources":["../src/wrangler-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAYpD,MAAM,CAAC,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAW,CAAC;AAE7D,MAAM,UAAU,cAAc,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAiB;IAC/G,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,SAAS;QACrB,IAAI,EAAE,MAAM,CAAC,MAAM;QACnB,kBAAkB,EAAE,MAAM,CAAC,iBAAiB;QAC5C,mBAAmB,EAAE,CAAC,eAAe,CAAC;QACtC,WAAW,EAAE,KAAK;QAClB,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;QACpD,aAAa,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;QAChC,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE;QAChH,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI;YACrB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,QAAQ,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;SACnJ,CAAC;QACF,GAAG,CAAC,YAAY,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,MAAM,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;KAC7G,CAAC;AACJ,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC;AACvG,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celsoft/platform",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Deploy apps to Cloudflare Workers with Neon Postgres, prod on push and a preview per pull request",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -17,7 +17,8 @@
17
17
  "platform": "./dist/cli.js"
18
18
  },
19
19
  "exports": {
20
- ".": "./dist/runtime/index.js"
20
+ ".": "./dist/runtime/index.js",
21
+ "./schema": "./dist/schema.js"
21
22
  },
22
23
  "files": [
23
24
  "dist",
@@ -30,14 +31,19 @@
30
31
  "@neondatabase/api-client": "^2.7.3",
31
32
  "better-auth": "^1.7.12",
32
33
  "cloudflare": "^7.3.0",
34
+ "drizzle-kit": "^0",
33
35
  "jsonc-parser": "^3.3.1",
34
36
  "pg": "^8.23.1",
35
- "postgres": "^3.4.9",
36
37
  "wrangler": "^4.152.0",
37
38
  "zod": "^4.6.7"
38
39
  },
39
40
  "devDependencies": {
41
+ "@cloudflare/workers-types": "^5.20261023.1",
40
42
  "@types/pg": "^8.23.1",
41
- "typescript": "7.0.2"
43
+ "typescript": "7.0.2",
44
+ "drizzle-orm": "^0.45.4"
45
+ },
46
+ "peerDependencies": {
47
+ "drizzle-orm": "^0"
42
48
  }
43
49
  }
package/schema.json CHANGED
@@ -5,10 +5,6 @@
5
5
  "$schema": {
6
6
  "type": "string"
7
7
  },
8
- "version": {
9
- "type": "number",
10
- "const": 1
11
- },
12
8
  "name": {
13
9
  "type": "string",
14
10
  "anyOf": [
@@ -65,16 +61,10 @@
65
61
  "pattern": "^\\$\\{[A-Z][A-Z0-9_]*\\}$"
66
62
  }
67
63
  ]
68
- },
69
- "migrate": {
70
- "type": "string",
71
- "minLength": 1,
72
- "description": "Command that runs migrations against $DATABASE_URL"
73
64
  }
74
65
  },
75
66
  "required": [
76
- "neonProject",
77
- "migrate"
67
+ "neonProject"
78
68
  ],
79
69
  "additionalProperties": false
80
70
  },
@@ -84,9 +74,24 @@
84
74
  "type": "boolean"
85
75
  },
86
76
  "auth": {
87
- "default": false,
88
77
  "description": "Sign-up and login with email and password; needs database and email",
89
- "type": "boolean"
78
+ "default": false,
79
+ "anyOf": [
80
+ {
81
+ "type": "boolean"
82
+ },
83
+ {
84
+ "type": "object",
85
+ "properties": {
86
+ "organizations": {
87
+ "default": false,
88
+ "description": "Organizations with members, roles, invitations and teams",
89
+ "type": "boolean"
90
+ }
91
+ },
92
+ "additionalProperties": false
93
+ }
94
+ ]
90
95
  },
91
96
  "files": {
92
97
  "default": false,
@@ -110,7 +115,6 @@
110
115
  }
111
116
  },
112
117
  "required": [
113
- "version",
114
118
  "name",
115
119
  "hostname",
116
120
  "worker",