@trokky/trokky 3.0.0 → 3.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/adapters/cloudflare-d1/cloudflare-d1-adapter.d.ts +132 -0
- package/dist/adapters/cloudflare-d1/cloudflare-d1-adapter.d.ts.map +1 -0
- package/dist/adapters/cloudflare-d1/cloudflare-d1-adapter.js +811 -0
- package/dist/adapters/cloudflare-d1/cloudflare-d1-adapter.js.map +1 -0
- package/dist/adapters/cloudflare-d1/index.d.ts +5 -0
- package/dist/adapters/cloudflare-d1/index.d.ts.map +1 -0
- package/dist/adapters/cloudflare-d1/index.js +12 -0
- package/dist/adapters/cloudflare-d1/index.js.map +1 -0
- package/dist/adapters/cloudflare-d1/rate-limit-store.d.ts +46 -0
- package/dist/adapters/cloudflare-d1/rate-limit-store.d.ts.map +1 -0
- package/dist/adapters/cloudflare-d1/rate-limit-store.js +96 -0
- package/dist/adapters/cloudflare-d1/rate-limit-store.js.map +1 -0
- package/dist/adapters/cloudflare-d1/types.d.ts +69 -0
- package/dist/adapters/cloudflare-d1/types.d.ts.map +1 -0
- package/dist/adapters/cloudflare-d1/types.js +2 -0
- package/dist/adapters/cloudflare-d1/types.js.map +1 -0
- package/dist/adapters/cloudflare-r2/cloudflare-r2-adapter.d.ts +86 -0
- package/dist/adapters/cloudflare-r2/cloudflare-r2-adapter.d.ts.map +1 -0
- package/dist/adapters/cloudflare-r2/cloudflare-r2-adapter.js +493 -0
- package/dist/adapters/cloudflare-r2/cloudflare-r2-adapter.js.map +1 -0
- package/dist/adapters/cloudflare-r2/index.d.ts +3 -0
- package/dist/adapters/cloudflare-r2/index.d.ts.map +1 -0
- package/dist/adapters/cloudflare-r2/index.js +11 -0
- package/dist/adapters/cloudflare-r2/index.js.map +1 -0
- package/dist/adapters/cloudflare-r2/types.d.ts +43 -0
- package/dist/adapters/cloudflare-r2/types.d.ts.map +1 -0
- package/dist/adapters/cloudflare-r2/types.js +2 -0
- package/dist/adapters/cloudflare-r2/types.js.map +1 -0
- package/dist/core/media/image-processor.d.ts.map +1 -1
- package/dist/core/media/image-processor.js +5 -13
- package/dist/core/media/image-processor.js.map +1 -1
- package/dist/core/media/processors/sharp.d.ts.map +1 -1
- package/dist/core/media/processors/sharp.js +13 -2
- package/dist/core/media/processors/sharp.js.map +1 -1
- package/dist/core/media/processors/types.d.ts +1 -1
- package/dist/core/media/processors/types.d.ts.map +1 -1
- package/dist/core/security/rate-limit-store.d.ts +56 -0
- package/dist/core/security/rate-limit-store.d.ts.map +1 -0
- package/dist/core/security/rate-limit-store.js +55 -0
- package/dist/core/security/rate-limit-store.js.map +1 -0
- package/dist/core/security/rate-limiter.d.ts +30 -2
- package/dist/core/security/rate-limiter.d.ts.map +1 -1
- package/dist/core/security/rate-limiter.js +50 -19
- package/dist/core/security/rate-limiter.js.map +1 -1
- package/dist/core/services/media-service.d.ts +34 -0
- package/dist/core/services/media-service.d.ts.map +1 -1
- package/dist/core/services/media-service.js +172 -120
- package/dist/core/services/media-service.js.map +1 -1
- package/dist/core/utils/retry.d.ts +45 -0
- package/dist/core/utils/retry.d.ts.map +1 -0
- package/dist/core/utils/retry.js +47 -0
- package/dist/core/utils/retry.js.map +1 -0
- package/dist/integrations/express/config.d.ts +31 -14
- package/dist/integrations/express/config.d.ts.map +1 -1
- package/dist/integrations/express/config.js +25 -8
- package/dist/integrations/express/config.js.map +1 -1
- package/dist/integrations/express/integration.d.ts.map +1 -1
- package/dist/integrations/express/integration.js +13 -6
- package/dist/integrations/express/integration.js.map +1 -1
- package/dist/integrations/express/server.d.ts.map +1 -1
- package/dist/integrations/express/server.js +5 -2
- package/dist/integrations/express/server.js.map +1 -1
- package/dist/integrations/express/types.d.ts +0 -5
- package/dist/integrations/express/types.d.ts.map +1 -1
- package/dist/integrations/workers/adapter.d.ts +28 -0
- package/dist/integrations/workers/adapter.d.ts.map +1 -0
- package/dist/integrations/workers/adapter.js +111 -0
- package/dist/integrations/workers/adapter.js.map +1 -0
- package/dist/integrations/workers/index.d.ts +22 -0
- package/dist/integrations/workers/index.d.ts.map +1 -0
- package/dist/integrations/workers/index.js +60 -0
- package/dist/integrations/workers/index.js.map +1 -0
- package/dist/routes/auth/auth-flow-store.d.ts +17 -0
- package/dist/routes/auth/auth-flow-store.d.ts.map +1 -1
- package/dist/routes/auth/auth-flow-store.js +27 -0
- package/dist/routes/auth/auth-flow-store.js.map +1 -1
- package/dist/routes/auth/oauth.d.ts.map +1 -1
- package/dist/routes/auth/oauth.js +5 -12
- package/dist/routes/auth/oauth.js.map +1 -1
- package/dist/routes/auth/passkey.d.ts.map +1 -1
- package/dist/routes/auth/passkey.js +5 -8
- package/dist/routes/auth/passkey.js.map +1 -1
- package/dist/structure/validation/schemas.d.ts +69 -69
- package/package.json +20 -1
- package/dist/core/media/processors/cloudflare-images.d.ts +0 -83
- package/dist/core/media/processors/cloudflare-images.d.ts.map +0 -1
- package/dist/core/media/processors/cloudflare-images.js +0 -241
- package/dist/core/media/processors/cloudflare-images.js.map +0 -1
- package/dist/core/media/processors/cloudflare-transform-store.d.ts +0 -127
- package/dist/core/media/processors/cloudflare-transform-store.d.ts.map +0 -1
- package/dist/core/media/processors/cloudflare-transform-store.js +0 -237
- package/dist/core/media/processors/cloudflare-transform-store.js.map +0 -1
- package/dist/core/media/processors/cloudflare-transformations.d.ts +0 -81
- package/dist/core/media/processors/cloudflare-transformations.d.ts.map +0 -1
- package/dist/core/media/processors/cloudflare-transformations.js +0 -144
- package/dist/core/media/processors/cloudflare-transformations.js.map +0 -1
- package/dist/core/media/processors/workers-images.d.ts +0 -112
- package/dist/core/media/processors/workers-images.d.ts.map +0 -1
- package/dist/core/media/processors/workers-images.js +0 -257
- package/dist/core/media/processors/workers-images.js.map +0 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare D1 data storage adapter.
|
|
3
|
+
*
|
|
4
|
+
* D1 is SQLite, which differs from Postgres in ways that are invisible until a
|
|
5
|
+
* conformance test fails, so the choices below are deliberate:
|
|
6
|
+
*
|
|
7
|
+
* - **Timestamps are generated in JS, never by SQL.** SQLite's `CURRENT_TIMESTAMP`
|
|
8
|
+
* has one-second resolution; the suite orders fixtures 20ms apart, so rows would
|
|
9
|
+
* tie and sort arbitrarily.
|
|
10
|
+
* - **Document payloads are one JSON TEXT blob.** Shredding fields into columns
|
|
11
|
+
* loses the distinction between `0`, `false`, `''`, `null` and absent, all of
|
|
12
|
+
* which must round-trip byte-identically.
|
|
13
|
+
* - **Filters compare value *and* `json_type`.** `json_extract` collapses JSON
|
|
14
|
+
* booleans to 0/1, so a naive equality makes `false` match a stored `0`.
|
|
15
|
+
* - **Sorts use `json_extract`**, which yields real SQL numbers; the text
|
|
16
|
+
* accessors would sort 13 before 2.
|
|
17
|
+
* - **There is no `beginTransaction`.** D1 has no interactive transactions, and
|
|
18
|
+
* the interface allows omitting it. The three places that need atomicity each
|
|
19
|
+
* do it in one statement: the document upsert, `saveUserIf`'s conditional
|
|
20
|
+
* UPDATE, and `consumeAuthFlowState`'s `DELETE … RETURNING`.
|
|
21
|
+
*/
|
|
22
|
+
import type { AppToken, AuditContext, CreateAppTokenData, CreateUserData, Document, DocumentData, ListOptions, UpdateUserData, User } from '../../core/types/index.js';
|
|
23
|
+
import type { AuthFlowState, DataStorageAdapter, SettingsConfig } from '../../core/types/storage-adapters.js';
|
|
24
|
+
import type { CloudflareD1AdapterConfig } from './types.js';
|
|
25
|
+
export declare class CloudflareD1Adapter implements DataStorageAdapter {
|
|
26
|
+
private readonly db;
|
|
27
|
+
private readonly tablePrefix;
|
|
28
|
+
private readonly autoMigrate;
|
|
29
|
+
private readonly logger;
|
|
30
|
+
private migrated;
|
|
31
|
+
private migrationPromise;
|
|
32
|
+
/** D1 rejects a single value over ~2MB, well below the 10MB other adapters allow. */
|
|
33
|
+
private readonly MAX_DOCUMENT_SIZE;
|
|
34
|
+
private readonly MAX_LIST_LIMIT;
|
|
35
|
+
constructor(config: CloudflareD1AdapterConfig);
|
|
36
|
+
private table;
|
|
37
|
+
private now;
|
|
38
|
+
/** Migrations run once; concurrent callers await the same promise. */
|
|
39
|
+
private ready;
|
|
40
|
+
/**
|
|
41
|
+
* Create the schema. No DEFAULTs on the JSON columns: a default of '{}' would
|
|
42
|
+
* turn an absent value into an empty object on read, where `undefined` is
|
|
43
|
+
* required.
|
|
44
|
+
*/
|
|
45
|
+
migrate(): Promise<void>;
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
healthCheck(): Promise<boolean>;
|
|
48
|
+
private mapRowToDocument;
|
|
49
|
+
getDocument(collection: string, id: string): Promise<Document | null>;
|
|
50
|
+
saveDocument(collection: string, id: string, data: DocumentData, auditContext?: AuditContext): Promise<Document>;
|
|
51
|
+
deleteDocument(collection: string, id: string): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Filter clauses shared by listDocuments and countDocuments so the two can
|
|
54
|
+
* never disagree. A data-field comparison checks `json_type` as well as the
|
|
55
|
+
* value: json_extract turns JSON true/false into 1/0, so value alone would
|
|
56
|
+
* make `false` match a stored `0`.
|
|
57
|
+
*/
|
|
58
|
+
private buildFilterClauses;
|
|
59
|
+
/**
|
|
60
|
+
* ORDER BY terms. Data fields go through json_extract, which yields a real SQL
|
|
61
|
+
* number, so 2 sorts before 13; the text accessors would not.
|
|
62
|
+
*/
|
|
63
|
+
private buildSortClause;
|
|
64
|
+
listDocuments(collection: string, options?: ListOptions): Promise<Document[]>;
|
|
65
|
+
countDocuments(collection: string, filter?: Record<string, unknown>): Promise<number>;
|
|
66
|
+
documentExists(collection: string, id: string): Promise<boolean>;
|
|
67
|
+
private mapRowToUser;
|
|
68
|
+
getUser(id: string): Promise<User | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Build the SET list from the keys actually present. A key holding `null`
|
|
71
|
+
* clears the column; a key that is absent, or present as `undefined`, leaves
|
|
72
|
+
* it alone. COALESCE cannot express that difference.
|
|
73
|
+
*/
|
|
74
|
+
private buildUserAssignments;
|
|
75
|
+
saveUser(id: string, userData: CreateUserData | Partial<UpdateUserData>): Promise<User>;
|
|
76
|
+
/**
|
|
77
|
+
* Compare-and-swap in one statement. SQLite makes a single UPDATE atomic, so
|
|
78
|
+
* no transaction is needed: the WHERE clause is the comparison, and RETURNING
|
|
79
|
+
* proves whether it matched.
|
|
80
|
+
*/
|
|
81
|
+
saveUserIf(id: string, userData: Partial<UpdateUserData>, condition: {
|
|
82
|
+
passwordHash: string;
|
|
83
|
+
}): Promise<User | null>;
|
|
84
|
+
listUsers(options?: {
|
|
85
|
+
role?: string;
|
|
86
|
+
isActive?: boolean;
|
|
87
|
+
limit?: number;
|
|
88
|
+
offset?: number;
|
|
89
|
+
}): Promise<User[]>;
|
|
90
|
+
deleteUser(id: string): Promise<void>;
|
|
91
|
+
private findUserBy;
|
|
92
|
+
getUserByUsername(username: string): Promise<User | null>;
|
|
93
|
+
getUserByEmail(email: string): Promise<User | null>;
|
|
94
|
+
isUsernameAvailable(username: string): Promise<boolean>;
|
|
95
|
+
isEmailAvailable(email: string): Promise<boolean>;
|
|
96
|
+
getUserByOAuthProvider(provider: string, providerId: string): Promise<User | null>;
|
|
97
|
+
getUserByPasskeyCredentialId(credentialId: string): Promise<User | null>;
|
|
98
|
+
private mapRowToAppToken;
|
|
99
|
+
getAppToken(id: string): Promise<AppToken | null>;
|
|
100
|
+
getAppTokenByHash(hash: string): Promise<AppToken | null>;
|
|
101
|
+
saveAppToken(id: string, data: CreateAppTokenData | Partial<AppToken>): Promise<AppToken>;
|
|
102
|
+
listAppTokens(options?: {
|
|
103
|
+
createdBy?: string;
|
|
104
|
+
isActive?: boolean;
|
|
105
|
+
limit?: number;
|
|
106
|
+
offset?: number;
|
|
107
|
+
}): Promise<AppToken[]>;
|
|
108
|
+
deleteAppToken(id: string): Promise<void>;
|
|
109
|
+
saveAuthFlowState(state: AuthFlowState): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* One statement, so two concurrent callers cannot both win. Kind and expiry
|
|
112
|
+
* are part of the WHERE clause: presenting another flow's id neither returns
|
|
113
|
+
* it nor destroys it.
|
|
114
|
+
*/
|
|
115
|
+
consumeAuthFlowState(id: string, kind: AuthFlowState['kind']): Promise<AuthFlowState | null>;
|
|
116
|
+
deleteExpiredAuthFlowStates(): Promise<number>;
|
|
117
|
+
getSettings(): Promise<SettingsConfig | null>;
|
|
118
|
+
saveSettings(settings: SettingsConfig): Promise<void>;
|
|
119
|
+
getStorageInfo(): Promise<{
|
|
120
|
+
[key: string]: unknown;
|
|
121
|
+
collections: string[];
|
|
122
|
+
documentCount: number;
|
|
123
|
+
userCount: number;
|
|
124
|
+
tokenCount: number;
|
|
125
|
+
storageSize?: number;
|
|
126
|
+
}>;
|
|
127
|
+
/** Not implemented: D1 has no interactive transactions. */
|
|
128
|
+
readonly beginTransaction: undefined;
|
|
129
|
+
/** Escape hatch for callers that need raw SQL, e.g. migrations. */
|
|
130
|
+
execute<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=cloudflare-d1-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-d1-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/cloudflare-d1/cloudflare-d1-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,cAAc,EACd,IAAI,EACL,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,cAAc,EACf,MAAM,sCAAsC,CAAA;AAC7C,OAAO,KAAK,EACV,yBAAyB,EAK1B,MAAM,YAAY,CAAA;AAqFnB,qBAAa,mBAAoB,YAAW,kBAAkB;IAC5D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAY;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IACjE,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,gBAAgB,CAA6B;IAErD,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAO;gBAE1B,MAAM,EAAE,yBAAyB;IAW7C,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,GAAG;IAIX,sEAAsE;YACxD,KAAK;IAoBnB;;;;OAIG;IACU,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAyExB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAa5C,OAAO,CAAC,gBAAgB;IAqBX,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAarE,YAAY,CACvB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,YAAY,EAClB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,QAAQ,CAAC;IA+CP,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1E;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAkC1B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAmCV,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAoBjF,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAarF,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe7E,OAAO,CAAC,YAAY;IAwBP,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAStD;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAuBf,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAuDpG;;;;OAIG;IACU,UAAU,CACrB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,OAAO,CAAC,cAAc,CAAC,EACjC,SAAS,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,GAClC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAiBV,SAAS,CACpB,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GACnF,OAAO,CAAC,IAAI,EAAE,CAAC;IA0BL,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAQpC,UAAU;IAYX,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAIzD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAInD,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIvD,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIjD,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAelF,4BAA4B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAoBrF,OAAO,CAAC,gBAAgB;IAmBX,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IASjD,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAmBzD,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IA4DzF,aAAa,CACxB,OAAO,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GACxF,OAAO,CAAC,QAAQ,EAAE,CAAC;IAuBT,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAcnE;;;;OAIG;IACU,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAoB5F,2BAA2B,IAAI,OAAO,CAAC,MAAM,CAAC;IAW9C,WAAW,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAQ7C,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAWrD,cAAc,IAAI,OAAO,CAAC;QACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;QACtB,WAAW,EAAE,MAAM,EAAE,CAAA;QACrB,aAAa,EAAE,MAAM,CAAA;QACrB,SAAS,EAAE,MAAM,CAAA;QACjB,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,CAAC;IAqBF,2DAA2D;IAC3D,SAAgB,gBAAgB,YAAY;IAE5C,mEAAmE;IACtD,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;CAQrF"}
|