@flytedesk/app-kit 0.1.3 → 0.2.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/cli/profile-sync.d.ts +2 -0
- package/dist/cli/profile-sync.js +26 -0
- package/dist/cli/profile-sync.js.map +1 -0
- package/dist/cli/sync-engine.d.ts +20 -0
- package/dist/cli/sync-engine.js +392 -0
- package/dist/cli/sync-engine.js.map +1 -0
- package/dist/cli/trace-sync.js +9 -359
- package/dist/cli/trace-sync.js.map +1 -1
- package/dist/profile/index.d.ts +36 -0
- package/dist/profile/index.js +36 -0
- package/dist/profile/index.js.map +1 -0
- package/dist/profile/plugin.d.ts +3 -0
- package/dist/profile/plugin.js +111 -0
- package/dist/profile/plugin.js.map +1 -0
- package/dist/profile/types.d.ts +76 -0
- package/dist/profile/types.js +10 -0
- package/dist/profile/types.js.map +1 -0
- package/package.json +7 -2
- package/prisma/fragments/profile.meta.json +4 -0
- package/prisma/fragments/profile.prisma +42 -0
- package/prisma/migrations/0002_app_kit_profile_init/migration.sql +15 -0
- package/prisma/migrations/manifest.json +8 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand-written row/option types for @flytedesk/app-kit/profile.
|
|
3
|
+
*
|
|
4
|
+
* Field names here mirror prisma/fragments/profile.prisma's camelCase model fields
|
|
5
|
+
* (userId/title/phone/timezone/bio/updatedAt) — a consumer's generated PrismaClient,
|
|
6
|
+
* once they've run `profile-sync init` and their own `prisma generate`, satisfies
|
|
7
|
+
* ProfileStore directly via `prisma.appKitUserProfile.findUnique` / `.upsert`.
|
|
8
|
+
*/
|
|
9
|
+
export interface ProfileRow {
|
|
10
|
+
userId: string;
|
|
11
|
+
title: string | null;
|
|
12
|
+
phone: string | null;
|
|
13
|
+
timezone: string | null;
|
|
14
|
+
bio: string | null;
|
|
15
|
+
updatedAt: Date;
|
|
16
|
+
}
|
|
17
|
+
/** The self-service fields a caller may write. */
|
|
18
|
+
export type ProfileFields = Pick<ProfileRow, "title" | "phone" | "timezone" | "bio">;
|
|
19
|
+
/** A PATCH body: any subset of ProfileFields, all still required to be strings
|
|
20
|
+
* (or absent) once validated — see parsePatchBody in ./plugin.ts. */
|
|
21
|
+
export type ProfilePatch = Partial<ProfileFields>;
|
|
22
|
+
/**
|
|
23
|
+
* Minimal persistence seam this plugin needs — deliberately NOT a dependency on
|
|
24
|
+
* `@prisma/client` (this package never builds its own PrismaClient; mirrors why
|
|
25
|
+
* src/trace/types.ts's TracePrismaClient and src/auth/types.ts's AuthStore are both
|
|
26
|
+
* ORM-agnostic structural interfaces rather than importing the generated client
|
|
27
|
+
* type). A consumer's generated PrismaClient trivially satisfies this shape:
|
|
28
|
+
*
|
|
29
|
+
* const store: ProfileStore = {
|
|
30
|
+
* findByUserId: (userId) => prisma.appKitUserProfile.findUnique({ where: { userId } }),
|
|
31
|
+
* upsert: (userId, patch) =>
|
|
32
|
+
* prisma.appKitUserProfile.upsert({
|
|
33
|
+
* where: { userId },
|
|
34
|
+
* create: { userId, ...patch },
|
|
35
|
+
* update: patch,
|
|
36
|
+
* }),
|
|
37
|
+
* };
|
|
38
|
+
*
|
|
39
|
+
* A hand-rolled adapter can back it with anything else (raw SQL, a different ORM,
|
|
40
|
+
* an in-memory store for tests — see src/profile/plugin.test.ts).
|
|
41
|
+
*/
|
|
42
|
+
export interface ProfileStore {
|
|
43
|
+
/** Must return `null`, not throw/404, when the user has no row yet — a person
|
|
44
|
+
* with no profile row still "has a profile," it's just all-null fields. */
|
|
45
|
+
findByUserId(userId: string): Promise<ProfileRow | null>;
|
|
46
|
+
/** Upserts the row for `userId`, writing only the fields present in `patch`
|
|
47
|
+
* (fields absent from `patch` are left unchanged on an existing row, and null
|
|
48
|
+
* on a newly-created one). */
|
|
49
|
+
upsert(userId: string, patch: ProfilePatch): Promise<ProfileRow>;
|
|
50
|
+
}
|
|
51
|
+
export interface AppKitProfileOptions {
|
|
52
|
+
/** The persistence seam — see ProfileStore above. Required. */
|
|
53
|
+
store: ProfileStore;
|
|
54
|
+
/**
|
|
55
|
+
* Base path the GET/PATCH routes are mounted under. Default "/profile".
|
|
56
|
+
*
|
|
57
|
+
* Deliberately not "/me": @flytedesk/app-kit/auth's own README/index.ts doc
|
|
58
|
+
* comment illustrates a consumer wiring up `GET /me` themselves, returning
|
|
59
|
+
* `request.authUser` (identity/roles/permissions — see src/auth/index.ts). That's
|
|
60
|
+
* a different resource than this plugin's editable title/phone/timezone/bio
|
|
61
|
+
* fields, so reusing "/me" here would be conceptually confusing even though nothing
|
|
62
|
+
* actually collides at registration time (auth doesn't register that route itself,
|
|
63
|
+
* it's just the example a consumer is expected to write).
|
|
64
|
+
*/
|
|
65
|
+
routePrefix?: string;
|
|
66
|
+
}
|
|
67
|
+
/** What GET/PATCH `{routePrefix}` return. Always 200 — see ProfileStore.findByUserId. */
|
|
68
|
+
export interface ProfileResponseBody {
|
|
69
|
+
userId: string;
|
|
70
|
+
title: string | null;
|
|
71
|
+
phone: string | null;
|
|
72
|
+
timezone: string | null;
|
|
73
|
+
bio: string | null;
|
|
74
|
+
/** ISO 8601, or `null` if the user has no row yet. */
|
|
75
|
+
updatedAt: string | null;
|
|
76
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand-written row/option types for @flytedesk/app-kit/profile.
|
|
3
|
+
*
|
|
4
|
+
* Field names here mirror prisma/fragments/profile.prisma's camelCase model fields
|
|
5
|
+
* (userId/title/phone/timezone/bio/updatedAt) — a consumer's generated PrismaClient,
|
|
6
|
+
* once they've run `profile-sync init` and their own `prisma generate`, satisfies
|
|
7
|
+
* ProfileStore directly via `prisma.appKitUserProfile.findUnique` / `.upsert`.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/profile/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flytedesk/app-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared platform kit for flytedesk apps: flytedesk-id auth (BFF/OIDC client) and a Postgres-native trace/audit layer.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"scripts"
|
|
29
29
|
],
|
|
30
30
|
"bin": {
|
|
31
|
-
"trace-sync": "./dist/cli/trace-sync.js"
|
|
31
|
+
"trace-sync": "./dist/cli/trace-sync.js",
|
|
32
|
+
"profile-sync": "./dist/cli/profile-sync.js"
|
|
32
33
|
},
|
|
33
34
|
"exports": {
|
|
34
35
|
"./auth": {
|
|
@@ -42,6 +43,10 @@
|
|
|
42
43
|
"./rate-limit": {
|
|
43
44
|
"types": "./dist/rate-limit/index.d.ts",
|
|
44
45
|
"import": "./dist/rate-limit/index.js"
|
|
46
|
+
},
|
|
47
|
+
"./profile": {
|
|
48
|
+
"types": "./dist/profile/index.d.ts",
|
|
49
|
+
"import": "./dist/profile/index.js"
|
|
45
50
|
}
|
|
46
51
|
},
|
|
47
52
|
"scripts": {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// @flytedesk/app-kit/profile — canonical Prisma model fragment (DEC-39, ported to a
|
|
2
|
+
// second fragment for the profile module).
|
|
3
|
+
//
|
|
4
|
+
// This fragment is NOT built into a Prisma Client by this package. It is copied
|
|
5
|
+
// verbatim into the consumer's own multi-file Prisma schema folder by `profile-sync
|
|
6
|
+
// init` (see src/cli/profile-sync.ts, which — like trace-sync — is a thin wrapper
|
|
7
|
+
// around the generalized src/cli/sync-engine.ts), and the consumer generates their
|
|
8
|
+
// own client against their own schema + this fragment merged in.
|
|
9
|
+
//
|
|
10
|
+
// What this models: title/phone/timezone/bio are cross-app, person-level facts —
|
|
11
|
+
// not specific to any one flytedesk product. The first real consumer is
|
|
12
|
+
// flytedesk-id, replacing its own local per-field storage for these with this
|
|
13
|
+
// shared table so other flytedesk apps don't each hand-roll their own GET/PATCH
|
|
14
|
+
// /me route + migration for the same handful of self-service profile fields.
|
|
15
|
+
//
|
|
16
|
+
// Design constraints (deliberate, see DEC-39 — same reasoning as trace.prisma):
|
|
17
|
+
// - No `@relation`/FK attributes anywhere. `userId` is a plain scalar matching
|
|
18
|
+
// the consuming app's own user-id type by convention, not a foreign key — a
|
|
19
|
+
// package that ships models into a consumer's schema cannot see the
|
|
20
|
+
// consumer's own User model to point a relation at.
|
|
21
|
+
// - No Prisma `enum`. None of these fields need one today, but the same
|
|
22
|
+
// schema-global-collision reasoning as trace.prisma applies if one is ever
|
|
23
|
+
// added here: it would stay a plain `String` column instead.
|
|
24
|
+
// - `String @id` (not `BigInt @default(autoincrement())`): unlike trace's
|
|
25
|
+
// high-write append log, this table has exactly one row per user, keyed
|
|
26
|
+
// directly on the consumer's own user id — no separate surrogate key earns
|
|
27
|
+
// its keep here.
|
|
28
|
+
//
|
|
29
|
+
// Table name is prefixed `app_kit_` via `@@map` so it can't collide with a
|
|
30
|
+
// consumer's own tables. Column names are snake_case via `@map`, matching the raw
|
|
31
|
+
// SQL in prisma/migrations/0002_app_kit_profile_init/migration.sql exactly.
|
|
32
|
+
|
|
33
|
+
model AppKitUserProfile {
|
|
34
|
+
userId String @id @map("user_id")
|
|
35
|
+
title String?
|
|
36
|
+
phone String?
|
|
37
|
+
timezone String?
|
|
38
|
+
bio String?
|
|
39
|
+
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")
|
|
40
|
+
|
|
41
|
+
@@map("app_kit_user_profile")
|
|
42
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- @flytedesk/app-kit/profile :: 0002_app_kit_profile_init
|
|
2
|
+
--
|
|
3
|
+
-- Hand-written raw SQL (this package does not run `prisma migrate dev` against its
|
|
4
|
+
-- own schema — see DEC-39, and 0001_app_kit_trace_init's migration.sql for the same
|
|
5
|
+
-- note on the trace fragment). Column names, types, and defaults match
|
|
6
|
+
-- prisma/fragments/profile.prisma exactly: TEXT for the String @id and the nullable
|
|
7
|
+
-- String columns, TIMESTAMPTZ for DateTime.
|
|
8
|
+
CREATE TABLE app_kit_user_profile (
|
|
9
|
+
user_id TEXT PRIMARY KEY,
|
|
10
|
+
title TEXT,
|
|
11
|
+
phone TEXT,
|
|
12
|
+
timezone TEXT,
|
|
13
|
+
bio TEXT,
|
|
14
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
15
|
+
);
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"id": "0001_app_kit_trace_init",
|
|
4
|
+
"fragment": "trace",
|
|
4
5
|
"file": "0001_app_kit_trace_init/migration.sql",
|
|
5
6
|
"checksum": "sha256:413918649af395583a2647f415ae4c8249477a922f1f5e25916742c535253915",
|
|
6
7
|
"introducedInFragmentVersion": "1.0.0"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"id": "0002_app_kit_profile_init",
|
|
11
|
+
"fragment": "profile",
|
|
12
|
+
"file": "0002_app_kit_profile_init/migration.sql",
|
|
13
|
+
"checksum": "sha256:62d688a2db89c77f12c61a3c98be5cfe84a6e06f8a4dda9d24b0f9acd5511b32",
|
|
14
|
+
"introducedInFragmentVersion": "1.0.0"
|
|
7
15
|
}
|
|
8
16
|
]
|