@undefineds.co/xpod 0.2.0-preview.2 → 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/README.md +24 -2
- package/dist/agents/AgentExecutorFactory.js +1 -1
- package/dist/agents/AgentExecutorFactory.js.map +1 -1
- package/dist/agents/AgentManager.js +1 -1
- package/dist/agents/AgentManager.js.map +1 -1
- package/dist/agents/config/agent-meta-schema.d.ts +7 -7
- package/dist/agents/config/agent-meta-schema.js +1 -1
- package/dist/agents/config/agent-meta-schema.js.map +1 -1
- package/dist/agents/config/resolve.js +1 -1
- package/dist/agents/config/resolve.js.map +1 -1
- package/dist/agents/schema/agent-config.d.ts +18 -18
- package/dist/agents/schema/agent-config.js +1 -1
- package/dist/agents/schema/agent-config.js.map +1 -1
- package/dist/agents/schema/tables.d.ts +8 -8
- package/dist/agents/schema/tables.js +1 -1
- package/dist/agents/schema/tables.js.map +1 -1
- package/dist/ai/schema/config.d.ts +7 -7
- package/dist/ai/schema/config.js +1 -1
- package/dist/ai/schema/config.js.map +1 -1
- package/dist/ai/schema/model.d.ts +13 -13
- package/dist/ai/schema/model.js +1 -1
- package/dist/ai/schema/model.js.map +1 -1
- package/dist/ai/schema/provider.d.ts +7 -7
- package/dist/ai/schema/provider.js +1 -1
- package/dist/ai/schema/provider.js.map +1 -1
- package/dist/ai/schema/vector-store.d.ts +17 -17
- package/dist/ai/schema/vector-store.js +1 -1
- package/dist/ai/schema/vector-store.js.map +1 -1
- package/dist/ai/service/CredentialReaderImpl.js +1 -1
- package/dist/ai/service/CredentialReaderImpl.js.map +1 -1
- package/dist/ai/service/DefaultAiConfigService.js.map +1 -1
- package/dist/api/ApiServer.d.ts +3 -1
- package/dist/api/ApiServer.js +14 -1
- package/dist/api/ApiServer.js.map +1 -1
- package/dist/api/chatkit/pod-store.d.ts +6 -0
- package/dist/api/chatkit/pod-store.js +86 -35
- package/dist/api/chatkit/pod-store.js.map +1 -1
- package/dist/api/chatkit/schema.d.ts +29 -29
- package/dist/api/chatkit/schema.js +4 -4
- package/dist/api/chatkit/schema.js.map +1 -1
- package/dist/api/container/common.js +1 -0
- package/dist/api/container/common.js.map +1 -1
- package/dist/api/runtime.js +21 -0
- package/dist/api/runtime.js.map +1 -1
- package/dist/api/service/VectorStoreService.js +1 -1
- package/dist/api/service/VectorStoreService.js.map +1 -1
- package/dist/cli/lib/pod-thread-store.js +1 -1
- package/dist/cli/lib/pod-thread-store.js.map +1 -1
- package/dist/credential/schema/tables.d.ts +14 -14
- package/dist/credential/schema/tables.js +1 -1
- package/dist/credential/schema/tables.js.map +1 -1
- package/dist/identity/drizzle/ServiceTokenRepository.js +9 -10
- package/dist/identity/drizzle/ServiceTokenRepository.js.map +1 -1
- package/dist/identity/drizzle/db.js +27 -2
- package/dist/identity/drizzle/db.js.map +1 -1
- package/dist/identity/drizzle/schema.pg.js +16 -16
- package/dist/identity/drizzle/schema.pg.js.map +1 -1
- package/dist/task/DrizzleTaskQueue.d.ts +1 -1
- package/dist/task/DrizzleTaskQueue.js +1 -1
- package/dist/task/DrizzleTaskQueue.js.map +1 -1
- package/dist/task/schema.d.ts +10 -10
- package/dist/task/schema.js +1 -1
- package/dist/task/schema.js.map +1 -1
- package/package.json +20 -10
|
@@ -24,8 +24,8 @@ class ServiceTokenRepository {
|
|
|
24
24
|
serviceType: options.serviceType,
|
|
25
25
|
serviceId: options.serviceId,
|
|
26
26
|
scopes: JSON.stringify(options.scopes),
|
|
27
|
-
createdAt:
|
|
28
|
-
expiresAt: options.expiresAt ?
|
|
27
|
+
createdAt: (0, db_1.toDbTimestamp)(this.db, new Date()),
|
|
28
|
+
expiresAt: options.expiresAt ? (0, db_1.toDbTimestamp)(this.db, options.expiresAt) : null,
|
|
29
29
|
});
|
|
30
30
|
this.logger.info(`Created service token ${id} for ${options.serviceType}:${options.serviceId}`);
|
|
31
31
|
return { id, token };
|
|
@@ -44,7 +44,7 @@ class ServiceTokenRepository {
|
|
|
44
44
|
.set({
|
|
45
45
|
tokenHash,
|
|
46
46
|
scopes: JSON.stringify(options.scopes),
|
|
47
|
-
expiresAt: options.expiresAt ?
|
|
47
|
+
expiresAt: options.expiresAt ? (0, db_1.toDbTimestamp)(this.db, options.expiresAt) : null,
|
|
48
48
|
})
|
|
49
49
|
.where((0, drizzle_orm_1.eq)(this.schema.serviceTokens.id, existing.id));
|
|
50
50
|
this.logger.info(`Updated service token ${existing.id} for ${options.serviceType}:${options.serviceId}`);
|
|
@@ -57,8 +57,8 @@ class ServiceTokenRepository {
|
|
|
57
57
|
serviceType: options.serviceType,
|
|
58
58
|
serviceId: options.serviceId,
|
|
59
59
|
scopes: JSON.stringify(options.scopes),
|
|
60
|
-
createdAt:
|
|
61
|
-
expiresAt: options.expiresAt ?
|
|
60
|
+
createdAt: (0, db_1.toDbTimestamp)(this.db, new Date()),
|
|
61
|
+
expiresAt: options.expiresAt ? (0, db_1.toDbTimestamp)(this.db, options.expiresAt) : null,
|
|
62
62
|
});
|
|
63
63
|
this.logger.info(`Registered service token ${id} for ${options.serviceType}:${options.serviceId}`);
|
|
64
64
|
return id;
|
|
@@ -77,7 +77,8 @@ class ServiceTokenRepository {
|
|
|
77
77
|
const row = rows[0];
|
|
78
78
|
// Check expiration (expiresAt is Unix timestamp in seconds)
|
|
79
79
|
if (row.expiresAt) {
|
|
80
|
-
const
|
|
80
|
+
const expiresAtValue = (0, db_1.fromDbTimestamp)(row.expiresAt);
|
|
81
|
+
const expiresAtMs = expiresAtValue?.getTime() ?? Number.NaN;
|
|
81
82
|
if (expiresAtMs < Date.now()) {
|
|
82
83
|
this.logger.debug(`Service token ${row.id} has expired`);
|
|
83
84
|
return undefined;
|
|
@@ -132,10 +133,8 @@ class ServiceTokenRepository {
|
|
|
132
133
|
serviceType: row.serviceType ?? row.service_type,
|
|
133
134
|
serviceId: row.serviceId ?? row.service_id,
|
|
134
135
|
scopes,
|
|
135
|
-
createdAt:
|
|
136
|
-
expiresAt: row.expiresAt
|
|
137
|
-
? (row.expiresAt instanceof Date ? row.expiresAt : new Date((row.expiresAt ?? row.expires_at) * 1000))
|
|
138
|
-
: null,
|
|
136
|
+
createdAt: (0, db_1.fromDbTimestamp)(row.createdAt ?? row.created_at) ?? new Date(0),
|
|
137
|
+
expiresAt: (0, db_1.fromDbTimestamp)(row.expiresAt ?? row.expires_at) ?? null,
|
|
139
138
|
};
|
|
140
139
|
}
|
|
141
140
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServiceTokenRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/ServiceTokenRepository.ts"],"names":[],"mappings":";;;AAAA,6CAAqD;AACrD,6CAAiC;AACjC,iEAAqD;AAErD,6BAAiC;AAoBjC,MAAa,sBAAsB;IAIjC,YAAoC,EAAoB;QAApB,OAAE,GAAF,EAAE,CAAkB;QAHvC,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAI3C,IAAI,CAAC,MAAM,GAAG,IAAA,cAAS,EAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,WAAW,CAAC,OAAkC;QACzD,MAAM,EAAE,GAAG,IAAA,wBAAU,GAAE,CAAC;QACxB,MAAM,KAAK,GAAG,OAAO,IAAA,wBAAU,GAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;QACtD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAExC,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;YACrD,EAAE;YACF,SAAS;YACT,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;YACtC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YACxC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;SACrF,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,QAAQ,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QAChG,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,aAAa,CACxB,KAAa,EACb,OAAkC;QAElC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAExC,mDAAmD;QACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QAClF,IAAI,QAAQ,EAAE,CAAC;YACb,4CAA4C;YAC5C,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;iBAC5C,GAAG,CAAC;gBACH,SAAS;gBACT,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;gBACtC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;aACrF,CAAC;iBACD,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;YACxD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,QAAQ,CAAC,EAAE,QAAQ,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YACzG,OAAO,QAAQ,CAAC,EAAE,CAAC;QACrB,CAAC;QAED,MAAM,EAAE,GAAG,IAAA,wBAAU,GAAE,CAAC;QACxB,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;YACrD,EAAE;YACF,SAAS;YACT,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;YACtC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YACxC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;SACrF,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE,QAAQ,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QACnG,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,WAAW,CAAC,KAAa;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAExC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE;aAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;aAC/B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QAE7D,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpB,4DAA4D;QAC5D,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;YAClB,MAAM,WAAW,GAAG,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;YACjH,IAAI,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC;gBACzD,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,aAAa,CAAC,WAAwB,EAAE,SAAiB;QACpE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE;aAChC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;aAC/B,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;QAEjE,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;QAC/D,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClD,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,WAAW,CAAC,EAAU;QACjC,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,IAAA,gBAAE,EAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5F,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,UAAU;QACrB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;YAChC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE;YAChC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,WAAW;YAClD,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS;YAC9C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM;YACxC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS;YAC9C,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS;SAC/C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAEnC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAEO,SAAS,CAAC,KAAa;QAC7B,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;IAEO,QAAQ,CAAC,GAAQ;QACvB,IAAI,MAAgB,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;QAChF,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,EAAE,CAAC;QACd,CAAC;QAED,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,YAAY;YAChD,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU;YAC1C,MAAM;YACN,SAAS,EAAE,GAAG,CAAC,SAAS,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;YAC7G,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU;gBACxC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,YAAY,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;gBACtG,CAAC,CAAC,IAAI;SACT,CAAC;IACJ,CAAC;CACF;AA7JD,wDA6JC","sourcesContent":["import { randomUUID, createHash } from 'node:crypto';\nimport { eq } from 'drizzle-orm';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { IdentityDatabase } from './db';\nimport { getSchema } from './db';\n\nexport type ServiceType = 'local' | 'business' | 'cloud' | 'compute';\n\nexport interface ServiceTokenRecord {\n id: string;\n serviceType: ServiceType;\n serviceId: string;\n scopes: string[];\n createdAt: Date;\n expiresAt: Date | null;\n}\n\nexport interface CreateServiceTokenOptions {\n serviceType: ServiceType;\n serviceId: string;\n scopes: string[];\n expiresAt?: Date | null;\n}\n\nexport class ServiceTokenRepository {\n private readonly logger = getLoggerFor(this);\n private readonly schema: ReturnType<typeof getSchema>;\n\n public constructor(private readonly db: IdentityDatabase) {\n this.schema = getSchema(db);\n }\n\n /**\n * Create a new service token. Returns the plaintext token (only available at creation time).\n */\n public async createToken(options: CreateServiceTokenOptions): Promise<{ id: string; token: string }> {\n const id = randomUUID();\n const token = `svc-${randomUUID().replace(/-/g, '')}`;\n const tokenHash = this.hashToken(token);\n\n await this.db.insert(this.schema.serviceTokens).values({\n id,\n tokenHash,\n serviceType: options.serviceType,\n serviceId: options.serviceId,\n scopes: JSON.stringify(options.scopes),\n createdAt: Math.floor(Date.now() / 1000),\n expiresAt: options.expiresAt ? Math.floor(options.expiresAt.getTime() / 1000) : null,\n });\n\n this.logger.info(`Created service token ${id} for ${options.serviceType}:${options.serviceId}`);\n return { id, token };\n }\n\n /**\n * Register a token from a known plaintext value (e.g. XPOD_BUSINESS_TOKEN env var).\n * Upserts by serviceType + serviceId to avoid duplicates.\n */\n public async registerToken(\n token: string,\n options: CreateServiceTokenOptions,\n ): Promise<string> {\n const tokenHash = this.hashToken(token);\n\n // Check if a token already exists for this service\n const existing = await this.findByService(options.serviceType, options.serviceId);\n if (existing) {\n // Update the hash in case the token changed\n await this.db.update(this.schema.serviceTokens)\n .set({\n tokenHash,\n scopes: JSON.stringify(options.scopes),\n expiresAt: options.expiresAt ? Math.floor(options.expiresAt.getTime() / 1000) : null,\n })\n .where(eq(this.schema.serviceTokens.id, existing.id));\n this.logger.info(`Updated service token ${existing.id} for ${options.serviceType}:${options.serviceId}`);\n return existing.id;\n }\n\n const id = randomUUID();\n await this.db.insert(this.schema.serviceTokens).values({\n id,\n tokenHash,\n serviceType: options.serviceType,\n serviceId: options.serviceId,\n scopes: JSON.stringify(options.scopes),\n createdAt: Math.floor(Date.now() / 1000),\n expiresAt: options.expiresAt ? Math.floor(options.expiresAt.getTime() / 1000) : null,\n });\n\n this.logger.info(`Registered service token ${id} for ${options.serviceType}:${options.serviceId}`);\n return id;\n }\n\n /**\n * Verify a plaintext token and return the matching record if valid.\n */\n public async verifyToken(token: string): Promise<ServiceTokenRecord | undefined> {\n const tokenHash = this.hashToken(token);\n\n const rows = await this.db.select()\n .from(this.schema.serviceTokens)\n .where(eq(this.schema.serviceTokens.tokenHash, tokenHash));\n\n if (!rows || rows.length === 0) {\n return undefined;\n }\n\n const row = rows[0];\n\n // Check expiration (expiresAt is Unix timestamp in seconds)\n if (row.expiresAt) {\n const expiresAtMs = typeof row.expiresAt === 'number' ? row.expiresAt * 1000 : new Date(row.expiresAt).getTime();\n if (expiresAtMs < Date.now()) {\n this.logger.debug(`Service token ${row.id} has expired`);\n return undefined;\n }\n }\n\n return this.toRecord(row);\n }\n\n /**\n * Find a token record by service type and service ID.\n */\n public async findByService(serviceType: ServiceType, serviceId: string): Promise<ServiceTokenRecord | undefined> {\n const rows = await this.db.select()\n .from(this.schema.serviceTokens)\n .where(eq(this.schema.serviceTokens.serviceType, serviceType));\n\n const match = rows.find((r: any) => r.serviceId === serviceId);\n return match ? this.toRecord(match) : undefined;\n }\n\n /**\n * Delete a service token by ID.\n */\n public async deleteToken(id: string): Promise<void> {\n await this.db.delete(this.schema.serviceTokens).where(eq(this.schema.serviceTokens.id, id));\n this.logger.info(`Deleted service token ${id}`);\n }\n\n /**\n * List all service tokens (without hashes).\n */\n public async listTokens(): Promise<ServiceTokenRecord[]> {\n const rows = await this.db.select({\n id: this.schema.serviceTokens.id,\n serviceType: this.schema.serviceTokens.serviceType,\n serviceId: this.schema.serviceTokens.serviceId,\n scopes: this.schema.serviceTokens.scopes,\n createdAt: this.schema.serviceTokens.createdAt,\n expiresAt: this.schema.serviceTokens.expiresAt,\n }).from(this.schema.serviceTokens);\n\n return rows.map((r: any) => this.toRecord(r));\n }\n\n private hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n }\n\n private toRecord(row: any): ServiceTokenRecord {\n let scopes: string[];\n try {\n scopes = typeof row.scopes === 'string' ? JSON.parse(row.scopes) : row.scopes;\n } catch {\n scopes = [];\n }\n\n return {\n id: row.id,\n serviceType: row.serviceType ?? row.service_type,\n serviceId: row.serviceId ?? row.service_id,\n scopes,\n createdAt: row.createdAt instanceof Date ? row.createdAt : new Date((row.createdAt ?? row.created_at) * 1000),\n expiresAt: row.expiresAt || row.expires_at\n ? (row.expiresAt instanceof Date ? row.expiresAt : new Date((row.expiresAt ?? row.expires_at) * 1000))\n : null,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ServiceTokenRepository.js","sourceRoot":"","sources":["../../../src/identity/drizzle/ServiceTokenRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID, createHash } from 'node:crypto';\nimport { eq } from 'drizzle-orm';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { IdentityDatabase } from './db';\nimport { getSchema, toDbTimestamp, fromDbTimestamp } from './db';\n\nexport type ServiceType = 'local' | 'business' | 'cloud' | 'compute';\n\nexport interface ServiceTokenRecord {\n id: string;\n serviceType: ServiceType;\n serviceId: string;\n scopes: string[];\n createdAt: Date;\n expiresAt: Date | null;\n}\n\nexport interface CreateServiceTokenOptions {\n serviceType: ServiceType;\n serviceId: string;\n scopes: string[];\n expiresAt?: Date | null;\n}\n\nexport class ServiceTokenRepository {\n private readonly logger = getLoggerFor(this);\n private readonly schema: ReturnType<typeof getSchema>;\n\n public constructor(private readonly db: IdentityDatabase) {\n this.schema = getSchema(db);\n }\n\n /**\n * Create a new service token. Returns the plaintext token (only available at creation time).\n */\n public async createToken(options: CreateServiceTokenOptions): Promise<{ id: string; token: string }> {\n const id = randomUUID();\n const token = `svc-${randomUUID().replace(/-/g, '')}`;\n const tokenHash = this.hashToken(token);\n\n await this.db.insert(this.schema.serviceTokens).values({\n id,\n tokenHash,\n serviceType: options.serviceType,\n serviceId: options.serviceId,\n scopes: JSON.stringify(options.scopes),\n createdAt: toDbTimestamp(this.db, new Date()),\n expiresAt: options.expiresAt ? toDbTimestamp(this.db, options.expiresAt) : null,\n });\n\n this.logger.info(`Created service token ${id} for ${options.serviceType}:${options.serviceId}`);\n return { id, token };\n }\n\n /**\n * Register a token from a known plaintext value (e.g. XPOD_BUSINESS_TOKEN env var).\n * Upserts by serviceType + serviceId to avoid duplicates.\n */\n public async registerToken(\n token: string,\n options: CreateServiceTokenOptions,\n ): Promise<string> {\n const tokenHash = this.hashToken(token);\n\n // Check if a token already exists for this service\n const existing = await this.findByService(options.serviceType, options.serviceId);\n if (existing) {\n // Update the hash in case the token changed\n await this.db.update(this.schema.serviceTokens)\n .set({\n tokenHash,\n scopes: JSON.stringify(options.scopes),\n expiresAt: options.expiresAt ? toDbTimestamp(this.db, options.expiresAt) : null,\n })\n .where(eq(this.schema.serviceTokens.id, existing.id));\n this.logger.info(`Updated service token ${existing.id} for ${options.serviceType}:${options.serviceId}`);\n return existing.id;\n }\n\n const id = randomUUID();\n await this.db.insert(this.schema.serviceTokens).values({\n id,\n tokenHash,\n serviceType: options.serviceType,\n serviceId: options.serviceId,\n scopes: JSON.stringify(options.scopes),\n createdAt: toDbTimestamp(this.db, new Date()),\n expiresAt: options.expiresAt ? toDbTimestamp(this.db, options.expiresAt) : null,\n });\n\n this.logger.info(`Registered service token ${id} for ${options.serviceType}:${options.serviceId}`);\n return id;\n }\n\n /**\n * Verify a plaintext token and return the matching record if valid.\n */\n public async verifyToken(token: string): Promise<ServiceTokenRecord | undefined> {\n const tokenHash = this.hashToken(token);\n\n const rows = await this.db.select()\n .from(this.schema.serviceTokens)\n .where(eq(this.schema.serviceTokens.tokenHash, tokenHash));\n\n if (!rows || rows.length === 0) {\n return undefined;\n }\n\n const row = rows[0];\n\n // Check expiration (expiresAt is Unix timestamp in seconds)\n if (row.expiresAt) {\n const expiresAtValue = fromDbTimestamp(row.expiresAt);\n const expiresAtMs = expiresAtValue?.getTime() ?? Number.NaN;\n if (expiresAtMs < Date.now()) {\n this.logger.debug(`Service token ${row.id} has expired`);\n return undefined;\n }\n }\n\n return this.toRecord(row);\n }\n\n /**\n * Find a token record by service type and service ID.\n */\n public async findByService(serviceType: ServiceType, serviceId: string): Promise<ServiceTokenRecord | undefined> {\n const rows = await this.db.select()\n .from(this.schema.serviceTokens)\n .where(eq(this.schema.serviceTokens.serviceType, serviceType));\n\n const match = rows.find((r: any) => r.serviceId === serviceId);\n return match ? this.toRecord(match) : undefined;\n }\n\n /**\n * Delete a service token by ID.\n */\n public async deleteToken(id: string): Promise<void> {\n await this.db.delete(this.schema.serviceTokens).where(eq(this.schema.serviceTokens.id, id));\n this.logger.info(`Deleted service token ${id}`);\n }\n\n /**\n * List all service tokens (without hashes).\n */\n public async listTokens(): Promise<ServiceTokenRecord[]> {\n const rows = await this.db.select({\n id: this.schema.serviceTokens.id,\n serviceType: this.schema.serviceTokens.serviceType,\n serviceId: this.schema.serviceTokens.serviceId,\n scopes: this.schema.serviceTokens.scopes,\n createdAt: this.schema.serviceTokens.createdAt,\n expiresAt: this.schema.serviceTokens.expiresAt,\n }).from(this.schema.serviceTokens);\n\n return rows.map((r: any) => this.toRecord(r));\n }\n\n private hashToken(token: string): string {\n return createHash('sha256').update(token).digest('hex');\n }\n\n private toRecord(row: any): ServiceTokenRecord {\n let scopes: string[];\n try {\n scopes = typeof row.scopes === 'string' ? JSON.parse(row.scopes) : row.scopes;\n } catch {\n scopes = [];\n }\n\n return {\n id: row.id,\n serviceType: row.serviceType ?? row.service_type,\n serviceId: row.serviceId ?? row.service_id,\n scopes,\n createdAt: fromDbTimestamp(row.createdAt ?? row.created_at) ?? new Date(0),\n expiresAt: fromDbTimestamp(row.expiresAt ?? row.expires_at) ?? null,\n };\n }\n}\n"]}
|
|
@@ -40,7 +40,6 @@ exports.fromDbTimestamp = fromDbTimestamp;
|
|
|
40
40
|
const pg_1 = require("pg");
|
|
41
41
|
const node_postgres_1 = require("drizzle-orm/node-postgres");
|
|
42
42
|
const better_sqlite3_1 = require("drizzle-orm/better-sqlite3");
|
|
43
|
-
const better_sqlite3_2 = __importDefault(require("better-sqlite3"));
|
|
44
43
|
const pgSchema = __importStar(require("./schema.pg"));
|
|
45
44
|
const sqliteSchema = __importStar(require("./schema.sqlite"));
|
|
46
45
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -65,6 +64,31 @@ for (const oid of JSON_OIDS) {
|
|
|
65
64
|
// and to satisfy PgQuintStore's parseVector expecting a string.
|
|
66
65
|
pg_1.types.setTypeParser(oid, (value) => value);
|
|
67
66
|
}
|
|
67
|
+
function wrapBetterSqliteError(error) {
|
|
68
|
+
if (!(error instanceof Error)) {
|
|
69
|
+
return new Error(String(error));
|
|
70
|
+
}
|
|
71
|
+
if (!/NODE_MODULE_VERSION|compiled against a different Node\.js version/i.test(error.message)) {
|
|
72
|
+
return error;
|
|
73
|
+
}
|
|
74
|
+
return new Error([
|
|
75
|
+
`Failed to load better-sqlite3 under Node ${process.version} (ABI ${process.versions.modules}).`,
|
|
76
|
+
'This usually means native modules were installed with a different Node.js major version.',
|
|
77
|
+
'Suggested fix:',
|
|
78
|
+
' 1. nvm use 22',
|
|
79
|
+
' 2. yarn install --force --ignore-engines',
|
|
80
|
+
'',
|
|
81
|
+
`Original error: ${error.message}`,
|
|
82
|
+
].join('\n'));
|
|
83
|
+
}
|
|
84
|
+
function loadBetterSqlite3() {
|
|
85
|
+
try {
|
|
86
|
+
return require('better-sqlite3');
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw wrapBetterSqliteError(error);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
68
92
|
/**
|
|
69
93
|
* Returns true if the connection string is a SQLite URL.
|
|
70
94
|
*/
|
|
@@ -89,7 +113,8 @@ function getIdentityDatabase(connectionString) {
|
|
|
89
113
|
node_fs_1.default.mkdirSync(directory, { recursive: true });
|
|
90
114
|
}
|
|
91
115
|
}
|
|
92
|
-
const
|
|
116
|
+
const BetterSqlite3 = loadBetterSqlite3();
|
|
117
|
+
const sqlite = new BetterSqlite3(isMemory ? ':memory:' : filename);
|
|
93
118
|
// Apply pragmas for better concurrency (prevents SQLITE_BUSY errors)
|
|
94
119
|
// WAL mode allows concurrent reads during writes
|
|
95
120
|
// busy_timeout waits up to 5 seconds before throwing SQLITE_BUSY
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/identity/drizzle/db.ts"],"names":[],"mappings":"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","sourcesContent":["import { Pool, types } from 'pg';\nimport { drizzle as drizzlePg } from 'drizzle-orm/node-postgres';\nimport { drizzle as drizzleSqlite, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport { NodePgDatabase } from 'drizzle-orm/node-postgres';\nimport type { SQL } from 'drizzle-orm/sql';\nimport Database from 'better-sqlite3';\nimport * as pgSchema from './schema.pg';\nimport * as sqliteSchema from './schema.sqlite';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { getSharedPool, releaseSharedPool } from '../../storage/database/PostgresPoolManager';\n\n// Use 'any' to allow both PostgreSQL and SQLite database instances\n// The actual type depends on the connection string at runtime\nexport type IdentityDatabase = any;\nexport type IdentitySchema = typeof pgSchema | typeof sqliteSchema;\n\n/**\n * Get the appropriate schema for the given database connection.\n * This provides a unified abstraction layer over PG and SQLite schemas.\n *\n * @example\n * const schema = getSchema(db);\n * await db.select().from(schema.accountUsage).where(eq(schema.accountUsage.accountId, id));\n */\nexport function getSchema(db: IdentityDatabase): typeof pgSchema | typeof sqliteSchema {\n return isDatabaseSqlite(db) ? sqliteSchema : pgSchema;\n}\n\n/**\n * Standardized query result format across databases.\n */\nexport interface QueryResult<T = Record<string, unknown>> {\n rows: T[];\n}\n\ninterface CachedConnection {\n db: IdentityDatabase;\n schema: IdentitySchema;\n isSqlite: boolean;\n close: () => Promise<void>;\n}\n\nconst dbCache = new Map<string, CachedConnection>();\nconst dbInitPromises = new WeakMap<object, Promise<void>>();\n\nconst JSON_OIDS = [114, 3802];\n\nfor (const oid of JSON_OIDS) {\n // Explicitly return raw string to avoid \"Type Conflict\" with CSS\n // and to satisfy PgQuintStore's parseVector expecting a string.\n types.setTypeParser(oid, (value) => value);\n}\n\n/**\n * Returns true if the connection string is a SQLite URL.\n */\nexport function isSqliteUrl(connectionString: string): boolean {\n return connectionString.startsWith('sqlite:');\n}\n\n/**\n * Get or create a Drizzle database connection with the appropriate schema.\n * Supports both PostgreSQL and SQLite.\n */\nexport function getIdentityDatabase(connectionString: string): IdentityDatabase {\n const cached = dbCache.get(connectionString);\n if (cached) {\n return cached.db;\n }\n\n if (isSqliteUrl(connectionString)) {\n const filename = connectionString.replace('sqlite:', '');\n const isMemory = filename === ':memory:' || filename.startsWith(':memory:');\n if (!isMemory) {\n const directory = path.dirname(filename);\n if (directory && !fs.existsSync(directory)) {\n fs.mkdirSync(directory, { recursive: true });\n }\n }\n const sqlite = new Database(isMemory ? ':memory:' : filename);\n\n // Apply pragmas for better concurrency (prevents SQLITE_BUSY errors)\n // WAL mode allows concurrent reads during writes\n // busy_timeout waits up to 5 seconds before throwing SQLITE_BUSY\n if (!isMemory) {\n sqlite.pragma('journal_mode = WAL');\n sqlite.pragma('busy_timeout = 5000');\n sqlite.pragma('synchronous = NORMAL');\n }\n\n const db = drizzleSqlite(sqlite);\n\n // Create tables if they don't exist\n ensureSqliteTables(sqlite);\n\n dbInitPromises.set(db as object, Promise.resolve());\n dbCache.set(connectionString, {\n db,\n schema: sqliteSchema,\n isSqlite: true,\n close: async () => { sqlite.close(); },\n });\n return db;\n }\n\n // PostgreSQL: use shared pool to avoid connection exhaustion and deadlocks\n const pool = getSharedPool({ connectionString });\n const db = drizzlePg(pool);\n const initPromise = (async(): Promise<void> => {\n await ensurePostgresTables(pool);\n await migratePgColumns(pool);\n })();\n dbInitPromises.set(db as object, initPromise);\n initPromise.catch((err) => {\n console.error(`[IdentityDB] PG migration failed: ${err}`);\n });\n dbCache.set(connectionString, {\n db,\n schema: pgSchema,\n isSqlite: false,\n close: async () => { \n // Release reference to shared pool instead of ending it\n releaseSharedPool({ connectionString }); \n },\n });\n return db;\n}\n\n/**\n * Get the schema for a given connection string.\n */\nexport function getIdentitySchema(connectionString: string): IdentitySchema {\n const cached = dbCache.get(connectionString);\n if (cached) {\n return cached.schema;\n }\n // Initialize connection to populate cache\n getIdentityDatabase(connectionString);\n return dbCache.get(connectionString)!.schema;\n}\n\n/**\n * Safely get a Drizzle database connection, returning undefined on error.\n * Use this when the identity database is optional (e.g., for usage tracking).\n */\nexport function tryGetIdentityDatabase(connectionString: string): IdentityDatabase | undefined {\n try {\n return getIdentityDatabase(connectionString);\n } catch {\n return undefined;\n }\n}\n\nexport async function closeAllIdentityConnections(): Promise<void> {\n await Promise.all([...dbCache.values()].map(({ close }) => close()));\n dbCache.clear();\n}\n\n/**\n * Check if a database connection is SQLite.\n * SQLite drizzle has `all()` method but no `execute()` method.\n * PostgreSQL drizzle has `execute()` method but no `all()` method.\n */\nexport function isDatabaseSqlite(db: IdentityDatabase): boolean {\n // SQLite drizzle has `all` method, PostgreSQL drizzle has `execute` method\n return typeof db.all === 'function' && typeof db.execute !== 'function';\n}\n\nasync function ensureDatabaseReady(db: IdentityDatabase): Promise<void> {\n const initPromise = dbInitPromises.get(db as object);\n if (initPromise) {\n await initPromise;\n }\n}\n\n/**\n * Execute a SQL query uniformly across PostgreSQL and SQLite.\n * Returns a standardized result with rows array.\n *\n * @example\n * const result = await executeQuery(db, sql`SELECT * FROM users WHERE id = ${userId}`);\n * if (result.rows.length > 0) { ... }\n */\nexport async function executeQuery<T = Record<string, unknown>>(\n db: IdentityDatabase,\n query: SQL,\n): Promise<QueryResult<T>> {\n await ensureDatabaseReady(db);\n if (isDatabaseSqlite(db)) {\n // SQLite: db.all() returns array directly\n const rows = db.all(query) as T[];\n return { rows };\n }\n // PostgreSQL: db.execute() returns { rows: [...] }\n return db.execute(query) as Promise<QueryResult<T>>;\n}\n\n/**\n * Execute a SQL statement that doesn't return rows (INSERT, UPDATE, DELETE).\n * Works uniformly across PostgreSQL and SQLite.\n */\nexport async function executeStatement(\n db: IdentityDatabase,\n query: SQL,\n): Promise<void> {\n await ensureDatabaseReady(db);\n if (isDatabaseSqlite(db)) {\n // SQLite: db.run() for statements\n db.run(query);\n return;\n }\n // PostgreSQL: db.execute() works for statements too\n await db.execute(query);\n}\n\n/**\n * Convert a Date to a value suitable for the database.\n * SQLite uses Unix timestamps (seconds), PostgreSQL uses Date objects.\n */\nexport function toDbTimestamp(db: IdentityDatabase, date: Date): number | Date {\n return isDatabaseSqlite(db) ? Math.floor(date.getTime() / 1000) : date;\n}\n\n/**\n * Parse a timestamp value from database result to Date.\n * Handles both Unix timestamps (SQLite) and Date objects (PostgreSQL).\n */\nexport function fromDbTimestamp(value: unknown): Date | undefined {\n if (value === null || value === undefined) {\n return undefined;\n }\n if (value instanceof Date) {\n return value;\n }\n if (typeof value === 'number') {\n return new Date(value * 1000);\n }\n if (typeof value === 'string') {\n return new Date(value);\n }\n return undefined;\n}\n\n/**\n * Ensure SQLite tables exist (simple DDL for local/dev mode).\n */\nfunction ensureSqliteTables(sqlite: Database.Database): void {\n sqlite.exec(`\n CREATE TABLE IF NOT EXISTS identity_account_usage (\n account_id TEXT PRIMARY KEY,\n storage_bytes INTEGER NOT NULL DEFAULT 0,\n ingress_bytes INTEGER NOT NULL DEFAULT 0,\n egress_bytes INTEGER NOT NULL DEFAULT 0,\n storage_limit_bytes INTEGER,\n bandwidth_limit_bps INTEGER,\n compute_seconds INTEGER NOT NULL DEFAULT 0,\n tokens_used INTEGER NOT NULL DEFAULT 0,\n compute_limit_seconds INTEGER,\n token_limit_monthly INTEGER,\n period_start INTEGER,\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n\n CREATE TABLE IF NOT EXISTS identity_pod_usage (\n pod_id TEXT PRIMARY KEY,\n account_id TEXT NOT NULL,\n storage_bytes INTEGER NOT NULL DEFAULT 0,\n ingress_bytes INTEGER NOT NULL DEFAULT 0,\n egress_bytes INTEGER NOT NULL DEFAULT 0,\n storage_limit_bytes INTEGER,\n bandwidth_limit_bps INTEGER,\n compute_seconds INTEGER NOT NULL DEFAULT 0,\n tokens_used INTEGER NOT NULL DEFAULT 0,\n compute_limit_seconds INTEGER,\n token_limit_monthly INTEGER,\n period_start INTEGER,\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node (\n id TEXT PRIMARY KEY,\n display_name TEXT,\n owner_account_id TEXT,\n token_hash TEXT NOT NULL,\n account_id TEXT,\n node_type TEXT DEFAULT 'edge',\n subdomain TEXT UNIQUE,\n access_mode TEXT,\n ipv4 TEXT,\n public_port INTEGER,\n public_url TEXT,\n service_token_hash TEXT,\n provision_code_hash TEXT,\n internal_ip TEXT,\n internal_port INTEGER,\n hostname TEXT,\n ipv6 TEXT,\n version TEXT,\n capabilities TEXT,\n metadata TEXT,\n connectivity_status TEXT DEFAULT 'unknown',\n last_connectivity_check INTEGER,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n last_seen INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node_pod (\n node_id TEXT NOT NULL REFERENCES identity_edge_node(id) ON DELETE CASCADE,\n base_url TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS api_client_credentials (\n client_id TEXT PRIMARY KEY,\n client_secret_encrypted TEXT NOT NULL,\n web_id TEXT NOT NULL,\n account_id TEXT NOT NULL,\n display_name TEXT,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n\n CREATE TABLE IF NOT EXISTS identity_service_token (\n id TEXT PRIMARY KEY,\n token_hash TEXT NOT NULL UNIQUE,\n service_type TEXT NOT NULL,\n service_id TEXT NOT NULL,\n scopes TEXT NOT NULL,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n expires_at INTEGER\n );\n `);\n\n // Migrate existing tables: add new columns if missing\n migrateSqliteColumns(sqlite);\n}\n\n/**\n * Add columns that may be missing from older databases.\n * SQLite ALTER TABLE ADD COLUMN is idempotent-safe via try/catch.\n */\nfunction migrateSqliteColumns(sqlite: Database.Database): void {\n const addColumn = (table: string, column: string, type: string): void => {\n try {\n sqlite.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`);\n } catch {\n // Column already exists — ignore\n }\n };\n\n addColumn('identity_edge_node', 'public_url', 'TEXT');\n addColumn('identity_edge_node', 'service_token_hash', 'TEXT');\n addColumn('identity_edge_node', 'provision_code_hash', 'TEXT');\n\n // Usage tables: compute/token columns\n addColumn('identity_account_usage', 'compute_seconds', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_account_usage', 'tokens_used', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_account_usage', 'compute_limit_seconds', 'INTEGER');\n addColumn('identity_account_usage', 'token_limit_monthly', 'INTEGER');\n addColumn('identity_account_usage', 'period_start', 'INTEGER');\n addColumn('identity_pod_usage', 'compute_seconds', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_pod_usage', 'tokens_used', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_pod_usage', 'compute_limit_seconds', 'INTEGER');\n addColumn('identity_pod_usage', 'token_limit_monthly', 'INTEGER');\n addColumn('identity_pod_usage', 'period_start', 'INTEGER');\n}\n\n/**\n * Add columns that may be missing from older PostgreSQL databases.\n * Uses IF NOT EXISTS via information_schema check + ALTER TABLE.\n */\nasync function migratePgColumns(pool: { query: (sql: string) => Promise<any> }): Promise<void> {\n const addColumn = async (table: string, column: string, type: string): Promise<void> => {\n try {\n await pool.query(\n `DO $$ BEGIN\n IF NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = '${table}' AND column_name = '${column}'\n ) THEN\n ALTER TABLE ${table} ADD COLUMN ${column} ${type};\n END IF;\n END $$;`,\n );\n } catch {\n // Ignore errors (table might not exist yet)\n }\n };\n\n // Usage tables: compute/token columns\n await addColumn('identity_account_usage', 'compute_seconds', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_account_usage', 'tokens_used', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_account_usage', 'compute_limit_seconds', 'BIGINT');\n await addColumn('identity_account_usage', 'token_limit_monthly', 'BIGINT');\n await addColumn('identity_account_usage', 'period_start', 'TIMESTAMP WITH TIME ZONE');\n await addColumn('identity_pod_usage', 'compute_seconds', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_pod_usage', 'tokens_used', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_pod_usage', 'compute_limit_seconds', 'BIGINT');\n await addColumn('identity_pod_usage', 'token_limit_monthly', 'BIGINT');\n await addColumn('identity_pod_usage', 'period_start', 'TIMESTAMP WITH TIME ZONE');\n\n // Service token table\n try {\n await pool.query(`\n CREATE TABLE IF NOT EXISTS identity_service_token (\n id TEXT PRIMARY KEY,\n token_hash TEXT NOT NULL UNIQUE,\n service_type TEXT NOT NULL,\n service_id TEXT NOT NULL,\n scopes TEXT NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMP WITH TIME ZONE\n );\n `);\n } catch {\n // Ignore if already exists\n }\n}\n\n\nasync function ensurePostgresTables(pool: Pool): Promise<void> {\n await pool.query(`\n CREATE TABLE IF NOT EXISTS identity_account_usage (\n account_id TEXT PRIMARY KEY,\n storage_bytes BIGINT NOT NULL DEFAULT 0,\n ingress_bytes BIGINT NOT NULL DEFAULT 0,\n egress_bytes BIGINT NOT NULL DEFAULT 0,\n storage_limit_bytes BIGINT,\n bandwidth_limit_bps BIGINT,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n );\n\n CREATE TABLE IF NOT EXISTS identity_pod_usage (\n pod_id TEXT PRIMARY KEY,\n account_id TEXT NOT NULL,\n storage_bytes BIGINT NOT NULL DEFAULT 0,\n ingress_bytes BIGINT NOT NULL DEFAULT 0,\n egress_bytes BIGINT NOT NULL DEFAULT 0,\n storage_limit_bytes BIGINT,\n bandwidth_limit_bps BIGINT,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node (\n id TEXT PRIMARY KEY,\n display_name TEXT,\n owner_account_id TEXT,\n token_hash TEXT NOT NULL,\n account_id TEXT,\n node_type TEXT DEFAULT 'edge',\n subdomain TEXT UNIQUE,\n access_mode TEXT,\n public_ip TEXT,\n public_port BIGINT,\n public_url TEXT,\n service_token_hash TEXT,\n provision_code_hash TEXT,\n internal_ip TEXT,\n internal_port BIGINT,\n capabilities JSONB,\n metadata JSONB,\n connectivity_status TEXT DEFAULT 'unknown',\n last_connectivity_check TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n last_seen TIMESTAMPTZ\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node_pod (\n node_id TEXT NOT NULL REFERENCES identity_edge_node(id) ON DELETE CASCADE,\n base_url TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS api_client_credentials (\n client_id TEXT PRIMARY KEY,\n client_secret_encrypted TEXT NOT NULL,\n web_id TEXT NOT NULL,\n account_id TEXT NOT NULL,\n display_name TEXT,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n );\n `);\n\n await migratePostgresColumns(pool);\n}\n\nasync function migratePostgresColumns(pool: Pool): Promise<void> {\n const addColumn = async (table: string, column: string, type: string): Promise<void> => {\n await pool.query(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${column} ${type}`);\n };\n\n await addColumn('identity_edge_node', 'public_url', 'TEXT');\n await addColumn('identity_edge_node', 'service_token_hash', 'TEXT');\n await addColumn('identity_edge_node', 'provision_code_hash', 'TEXT');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/identity/drizzle/db.ts"],"names":[],"mappings":"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","sourcesContent":["import { Pool, types } from 'pg';\nimport { drizzle as drizzlePg } from 'drizzle-orm/node-postgres';\nimport { drizzle as drizzleSqlite, BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';\nimport { NodePgDatabase } from 'drizzle-orm/node-postgres';\nimport type { SQL } from 'drizzle-orm/sql';\nimport * as pgSchema from './schema.pg';\nimport * as sqliteSchema from './schema.sqlite';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport { getSharedPool, releaseSharedPool } from '../../storage/database/PostgresPoolManager';\n\n// Use 'any' to allow both PostgreSQL and SQLite database instances\n// The actual type depends on the connection string at runtime\nexport type IdentityDatabase = any;\nexport type IdentitySchema = typeof pgSchema | typeof sqliteSchema;\n\n/**\n * Get the appropriate schema for the given database connection.\n * This provides a unified abstraction layer over PG and SQLite schemas.\n *\n * @example\n * const schema = getSchema(db);\n * await db.select().from(schema.accountUsage).where(eq(schema.accountUsage.accountId, id));\n */\nexport function getSchema(db: IdentityDatabase): typeof pgSchema | typeof sqliteSchema {\n return isDatabaseSqlite(db) ? sqliteSchema : pgSchema;\n}\n\n/**\n * Standardized query result format across databases.\n */\nexport interface QueryResult<T = Record<string, unknown>> {\n rows: T[];\n}\n\ninterface CachedConnection {\n db: IdentityDatabase;\n schema: IdentitySchema;\n isSqlite: boolean;\n close: () => Promise<void>;\n}\n\nconst dbCache = new Map<string, CachedConnection>();\nconst dbInitPromises = new WeakMap<object, Promise<void>>();\n\nconst JSON_OIDS = [114, 3802];\n\ntype SqliteDdlExecutor = { exec: (sql: string) => unknown };\n\nfor (const oid of JSON_OIDS) {\n // Explicitly return raw string to avoid \"Type Conflict\" with CSS\n // and to satisfy PgQuintStore's parseVector expecting a string.\n types.setTypeParser(oid, (value) => value);\n}\n\nfunction wrapBetterSqliteError(error: unknown): Error {\n if (!(error instanceof Error)) {\n return new Error(String(error));\n }\n\n if (!/NODE_MODULE_VERSION|compiled against a different Node\\.js version/i.test(error.message)) {\n return error;\n }\n\n return new Error([\n `Failed to load better-sqlite3 under Node ${process.version} (ABI ${process.versions.modules}).`,\n 'This usually means native modules were installed with a different Node.js major version.',\n 'Suggested fix:',\n ' 1. nvm use 22',\n ' 2. yarn install --force --ignore-engines',\n '',\n `Original error: ${error.message}`,\n ].join('\\n'));\n}\n\nfunction loadBetterSqlite3(): any {\n try {\n return require('better-sqlite3');\n } catch (error) {\n throw wrapBetterSqliteError(error);\n }\n}\n\n/**\n * Returns true if the connection string is a SQLite URL.\n */\nexport function isSqliteUrl(connectionString: string): boolean {\n return connectionString.startsWith('sqlite:');\n}\n\n/**\n * Get or create a Drizzle database connection with the appropriate schema.\n * Supports both PostgreSQL and SQLite.\n */\nexport function getIdentityDatabase(connectionString: string): IdentityDatabase {\n const cached = dbCache.get(connectionString);\n if (cached) {\n return cached.db;\n }\n\n if (isSqliteUrl(connectionString)) {\n const filename = connectionString.replace('sqlite:', '');\n const isMemory = filename === ':memory:' || filename.startsWith(':memory:');\n if (!isMemory) {\n const directory = path.dirname(filename);\n if (directory && !fs.existsSync(directory)) {\n fs.mkdirSync(directory, { recursive: true });\n }\n }\n const BetterSqlite3 = loadBetterSqlite3();\n const sqlite = new BetterSqlite3(isMemory ? ':memory:' : filename);\n\n // Apply pragmas for better concurrency (prevents SQLITE_BUSY errors)\n // WAL mode allows concurrent reads during writes\n // busy_timeout waits up to 5 seconds before throwing SQLITE_BUSY\n if (!isMemory) {\n sqlite.pragma('journal_mode = WAL');\n sqlite.pragma('busy_timeout = 5000');\n sqlite.pragma('synchronous = NORMAL');\n }\n\n const db = drizzleSqlite(sqlite);\n\n // Create tables if they don't exist\n ensureSqliteTables(sqlite);\n\n dbInitPromises.set(db as object, Promise.resolve());\n dbCache.set(connectionString, {\n db,\n schema: sqliteSchema,\n isSqlite: true,\n close: async () => { sqlite.close(); },\n });\n return db;\n }\n\n // PostgreSQL: use shared pool to avoid connection exhaustion and deadlocks\n const pool = getSharedPool({ connectionString });\n const db = drizzlePg(pool);\n const initPromise = (async(): Promise<void> => {\n await ensurePostgresTables(pool);\n await migratePgColumns(pool);\n })();\n dbInitPromises.set(db as object, initPromise);\n initPromise.catch((err) => {\n console.error(`[IdentityDB] PG migration failed: ${err}`);\n });\n dbCache.set(connectionString, {\n db,\n schema: pgSchema,\n isSqlite: false,\n close: async () => { \n // Release reference to shared pool instead of ending it\n releaseSharedPool({ connectionString }); \n },\n });\n return db;\n}\n\n/**\n * Get the schema for a given connection string.\n */\nexport function getIdentitySchema(connectionString: string): IdentitySchema {\n const cached = dbCache.get(connectionString);\n if (cached) {\n return cached.schema;\n }\n // Initialize connection to populate cache\n getIdentityDatabase(connectionString);\n return dbCache.get(connectionString)!.schema;\n}\n\n/**\n * Safely get a Drizzle database connection, returning undefined on error.\n * Use this when the identity database is optional (e.g., for usage tracking).\n */\nexport function tryGetIdentityDatabase(connectionString: string): IdentityDatabase | undefined {\n try {\n return getIdentityDatabase(connectionString);\n } catch {\n return undefined;\n }\n}\n\nexport async function closeAllIdentityConnections(): Promise<void> {\n await Promise.all([...dbCache.values()].map(({ close }) => close()));\n dbCache.clear();\n}\n\n/**\n * Check if a database connection is SQLite.\n * SQLite drizzle has `all()` method but no `execute()` method.\n * PostgreSQL drizzle has `execute()` method but no `all()` method.\n */\nexport function isDatabaseSqlite(db: IdentityDatabase): boolean {\n // SQLite drizzle has `all` method, PostgreSQL drizzle has `execute` method\n return typeof db.all === 'function' && typeof db.execute !== 'function';\n}\n\nasync function ensureDatabaseReady(db: IdentityDatabase): Promise<void> {\n const initPromise = dbInitPromises.get(db as object);\n if (initPromise) {\n await initPromise;\n }\n}\n\n/**\n * Execute a SQL query uniformly across PostgreSQL and SQLite.\n * Returns a standardized result with rows array.\n *\n * @example\n * const result = await executeQuery(db, sql`SELECT * FROM users WHERE id = ${userId}`);\n * if (result.rows.length > 0) { ... }\n */\nexport async function executeQuery<T = Record<string, unknown>>(\n db: IdentityDatabase,\n query: SQL,\n): Promise<QueryResult<T>> {\n await ensureDatabaseReady(db);\n if (isDatabaseSqlite(db)) {\n // SQLite: db.all() returns array directly\n const rows = db.all(query) as T[];\n return { rows };\n }\n // PostgreSQL: db.execute() returns { rows: [...] }\n return db.execute(query) as Promise<QueryResult<T>>;\n}\n\n/**\n * Execute a SQL statement that doesn't return rows (INSERT, UPDATE, DELETE).\n * Works uniformly across PostgreSQL and SQLite.\n */\nexport async function executeStatement(\n db: IdentityDatabase,\n query: SQL,\n): Promise<void> {\n await ensureDatabaseReady(db);\n if (isDatabaseSqlite(db)) {\n // SQLite: db.run() for statements\n db.run(query);\n return;\n }\n // PostgreSQL: db.execute() works for statements too\n await db.execute(query);\n}\n\n/**\n * Convert a Date to a value suitable for the database.\n * SQLite uses Unix timestamps (seconds), PostgreSQL uses Date objects.\n */\nexport function toDbTimestamp(db: IdentityDatabase, date: Date): number | Date {\n return isDatabaseSqlite(db) ? Math.floor(date.getTime() / 1000) : date;\n}\n\n/**\n * Parse a timestamp value from database result to Date.\n * Handles both Unix timestamps (SQLite) and Date objects (PostgreSQL).\n */\nexport function fromDbTimestamp(value: unknown): Date | undefined {\n if (value === null || value === undefined) {\n return undefined;\n }\n if (value instanceof Date) {\n return value;\n }\n if (typeof value === 'number') {\n return new Date(value * 1000);\n }\n if (typeof value === 'string') {\n return new Date(value);\n }\n return undefined;\n}\n\n/**\n * Ensure SQLite tables exist (simple DDL for local/dev mode).\n */\nfunction ensureSqliteTables(sqlite: SqliteDdlExecutor): void {\n sqlite.exec(`\n CREATE TABLE IF NOT EXISTS identity_account_usage (\n account_id TEXT PRIMARY KEY,\n storage_bytes INTEGER NOT NULL DEFAULT 0,\n ingress_bytes INTEGER NOT NULL DEFAULT 0,\n egress_bytes INTEGER NOT NULL DEFAULT 0,\n storage_limit_bytes INTEGER,\n bandwidth_limit_bps INTEGER,\n compute_seconds INTEGER NOT NULL DEFAULT 0,\n tokens_used INTEGER NOT NULL DEFAULT 0,\n compute_limit_seconds INTEGER,\n token_limit_monthly INTEGER,\n period_start INTEGER,\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n\n CREATE TABLE IF NOT EXISTS identity_pod_usage (\n pod_id TEXT PRIMARY KEY,\n account_id TEXT NOT NULL,\n storage_bytes INTEGER NOT NULL DEFAULT 0,\n ingress_bytes INTEGER NOT NULL DEFAULT 0,\n egress_bytes INTEGER NOT NULL DEFAULT 0,\n storage_limit_bytes INTEGER,\n bandwidth_limit_bps INTEGER,\n compute_seconds INTEGER NOT NULL DEFAULT 0,\n tokens_used INTEGER NOT NULL DEFAULT 0,\n compute_limit_seconds INTEGER,\n token_limit_monthly INTEGER,\n period_start INTEGER,\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node (\n id TEXT PRIMARY KEY,\n display_name TEXT,\n owner_account_id TEXT,\n token_hash TEXT NOT NULL,\n account_id TEXT,\n node_type TEXT DEFAULT 'edge',\n subdomain TEXT UNIQUE,\n access_mode TEXT,\n ipv4 TEXT,\n public_port INTEGER,\n public_url TEXT,\n service_token_hash TEXT,\n provision_code_hash TEXT,\n internal_ip TEXT,\n internal_port INTEGER,\n hostname TEXT,\n ipv6 TEXT,\n version TEXT,\n capabilities TEXT,\n metadata TEXT,\n connectivity_status TEXT DEFAULT 'unknown',\n last_connectivity_check INTEGER,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n last_seen INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node_pod (\n node_id TEXT NOT NULL REFERENCES identity_edge_node(id) ON DELETE CASCADE,\n base_url TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS api_client_credentials (\n client_id TEXT PRIMARY KEY,\n client_secret_encrypted TEXT NOT NULL,\n web_id TEXT NOT NULL,\n account_id TEXT NOT NULL,\n display_name TEXT,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n );\n\n CREATE TABLE IF NOT EXISTS identity_service_token (\n id TEXT PRIMARY KEY,\n token_hash TEXT NOT NULL UNIQUE,\n service_type TEXT NOT NULL,\n service_id TEXT NOT NULL,\n scopes TEXT NOT NULL,\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\n expires_at INTEGER\n );\n `);\n\n // Migrate existing tables: add new columns if missing\n migrateSqliteColumns(sqlite);\n}\n\n/**\n * Add columns that may be missing from older databases.\n * SQLite ALTER TABLE ADD COLUMN is idempotent-safe via try/catch.\n */\nfunction migrateSqliteColumns(sqlite: SqliteDdlExecutor): void {\n const addColumn = (table: string, column: string, type: string): void => {\n try {\n sqlite.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`);\n } catch {\n // Column already exists — ignore\n }\n };\n\n addColumn('identity_edge_node', 'public_url', 'TEXT');\n addColumn('identity_edge_node', 'service_token_hash', 'TEXT');\n addColumn('identity_edge_node', 'provision_code_hash', 'TEXT');\n\n // Usage tables: compute/token columns\n addColumn('identity_account_usage', 'compute_seconds', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_account_usage', 'tokens_used', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_account_usage', 'compute_limit_seconds', 'INTEGER');\n addColumn('identity_account_usage', 'token_limit_monthly', 'INTEGER');\n addColumn('identity_account_usage', 'period_start', 'INTEGER');\n addColumn('identity_pod_usage', 'compute_seconds', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_pod_usage', 'tokens_used', 'INTEGER NOT NULL DEFAULT 0');\n addColumn('identity_pod_usage', 'compute_limit_seconds', 'INTEGER');\n addColumn('identity_pod_usage', 'token_limit_monthly', 'INTEGER');\n addColumn('identity_pod_usage', 'period_start', 'INTEGER');\n}\n\n/**\n * Add columns that may be missing from older PostgreSQL databases.\n * Uses IF NOT EXISTS via information_schema check + ALTER TABLE.\n */\nasync function migratePgColumns(pool: { query: (sql: string) => Promise<any> }): Promise<void> {\n const addColumn = async (table: string, column: string, type: string): Promise<void> => {\n try {\n await pool.query(\n `DO $$ BEGIN\n IF NOT EXISTS (\n SELECT 1 FROM information_schema.columns\n WHERE table_name = '${table}' AND column_name = '${column}'\n ) THEN\n ALTER TABLE ${table} ADD COLUMN ${column} ${type};\n END IF;\n END $$;`,\n );\n } catch {\n // Ignore errors (table might not exist yet)\n }\n };\n\n // Usage tables: compute/token columns\n await addColumn('identity_account_usage', 'compute_seconds', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_account_usage', 'tokens_used', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_account_usage', 'compute_limit_seconds', 'BIGINT');\n await addColumn('identity_account_usage', 'token_limit_monthly', 'BIGINT');\n await addColumn('identity_account_usage', 'period_start', 'TIMESTAMP WITH TIME ZONE');\n await addColumn('identity_pod_usage', 'compute_seconds', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_pod_usage', 'tokens_used', 'BIGINT NOT NULL DEFAULT 0');\n await addColumn('identity_pod_usage', 'compute_limit_seconds', 'BIGINT');\n await addColumn('identity_pod_usage', 'token_limit_monthly', 'BIGINT');\n await addColumn('identity_pod_usage', 'period_start', 'TIMESTAMP WITH TIME ZONE');\n\n // Service token table\n try {\n await pool.query(`\n CREATE TABLE IF NOT EXISTS identity_service_token (\n id TEXT PRIMARY KEY,\n token_hash TEXT NOT NULL UNIQUE,\n service_type TEXT NOT NULL,\n service_id TEXT NOT NULL,\n scopes TEXT NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMP WITH TIME ZONE\n );\n `);\n } catch {\n // Ignore if already exists\n }\n}\n\n\nasync function ensurePostgresTables(pool: Pool): Promise<void> {\n await pool.query(`\n CREATE TABLE IF NOT EXISTS identity_account_usage (\n account_id TEXT PRIMARY KEY,\n storage_bytes BIGINT NOT NULL DEFAULT 0,\n ingress_bytes BIGINT NOT NULL DEFAULT 0,\n egress_bytes BIGINT NOT NULL DEFAULT 0,\n storage_limit_bytes BIGINT,\n bandwidth_limit_bps BIGINT,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n );\n\n CREATE TABLE IF NOT EXISTS identity_pod_usage (\n pod_id TEXT PRIMARY KEY,\n account_id TEXT NOT NULL,\n storage_bytes BIGINT NOT NULL DEFAULT 0,\n ingress_bytes BIGINT NOT NULL DEFAULT 0,\n egress_bytes BIGINT NOT NULL DEFAULT 0,\n storage_limit_bytes BIGINT,\n bandwidth_limit_bps BIGINT,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node (\n id TEXT PRIMARY KEY,\n display_name TEXT,\n owner_account_id TEXT,\n token_hash TEXT NOT NULL,\n account_id TEXT,\n node_type TEXT DEFAULT 'edge',\n subdomain TEXT UNIQUE,\n access_mode TEXT,\n public_ip TEXT,\n public_port BIGINT,\n public_url TEXT,\n service_token_hash TEXT,\n provision_code_hash TEXT,\n internal_ip TEXT,\n internal_port BIGINT,\n capabilities JSONB,\n metadata JSONB,\n connectivity_status TEXT DEFAULT 'unknown',\n last_connectivity_check TIMESTAMPTZ,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n last_seen TIMESTAMPTZ\n );\n\n CREATE TABLE IF NOT EXISTS identity_edge_node_pod (\n node_id TEXT NOT NULL REFERENCES identity_edge_node(id) ON DELETE CASCADE,\n base_url TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS api_client_credentials (\n client_id TEXT PRIMARY KEY,\n client_secret_encrypted TEXT NOT NULL,\n web_id TEXT NOT NULL,\n account_id TEXT NOT NULL,\n display_name TEXT,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n );\n `);\n\n await migratePostgresColumns(pool);\n}\n\nasync function migratePostgresColumns(pool: Pool): Promise<void> {\n const addColumn = async (table: string, column: string, type: string): Promise<void> => {\n await pool.query(`ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${column} ${type}`);\n };\n\n await addColumn('identity_edge_node', 'public_url', 'TEXT');\n await addColumn('identity_edge_node', 'service_token_hash', 'TEXT');\n await addColumn('identity_edge_node', 'provision_code_hash', 'TEXT');\n}\n"]}
|
|
@@ -15,8 +15,8 @@ exports.accountUsage = (0, pg_core_1.pgTable)('identity_account_usage', {
|
|
|
15
15
|
tokensUsed: (0, bigint_1.bigint)('tokens_used', { mode: 'number' }).notNull().default(0),
|
|
16
16
|
computeLimitSeconds: (0, bigint_1.bigint)('compute_limit_seconds', { mode: 'number' }),
|
|
17
17
|
tokenLimitMonthly: (0, bigint_1.bigint)('token_limit_monthly', { mode: 'number' }),
|
|
18
|
-
periodStart: (0,
|
|
19
|
-
updatedAt: (0,
|
|
18
|
+
periodStart: (0, pg_core_1.timestamp)('period_start', { withTimezone: true, mode: 'date' }),
|
|
19
|
+
updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
20
20
|
});
|
|
21
21
|
exports.podUsage = (0, pg_core_1.pgTable)('identity_pod_usage', {
|
|
22
22
|
podId: (0, pg_core_1.text)('pod_id').primaryKey(),
|
|
@@ -30,8 +30,8 @@ exports.podUsage = (0, pg_core_1.pgTable)('identity_pod_usage', {
|
|
|
30
30
|
tokensUsed: (0, bigint_1.bigint)('tokens_used', { mode: 'number' }).notNull().default(0),
|
|
31
31
|
computeLimitSeconds: (0, bigint_1.bigint)('compute_limit_seconds', { mode: 'number' }),
|
|
32
32
|
tokenLimitMonthly: (0, bigint_1.bigint)('token_limit_monthly', { mode: 'number' }),
|
|
33
|
-
periodStart: (0,
|
|
34
|
-
updatedAt: (0,
|
|
33
|
+
periodStart: (0, pg_core_1.timestamp)('period_start', { withTimezone: true, mode: 'date' }),
|
|
34
|
+
updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
35
35
|
});
|
|
36
36
|
/**
|
|
37
37
|
* WebID Profile 托管表
|
|
@@ -45,8 +45,8 @@ exports.webidProfiles = (0, pg_core_1.pgTable)('identity_webid_profile', {
|
|
|
45
45
|
oidcIssuer: (0, pg_core_1.text)('oidc_issuer'), // https://id.undefineds.co/
|
|
46
46
|
profileData: (0, pg_core_1.text)('profile_data'), // WebID Profile 的 JSON-LD 表示 (stored as JSON string)
|
|
47
47
|
accountId: (0, pg_core_1.text)('account_id'), // 关联的 CSS 账户 ID
|
|
48
|
-
createdAt: (0,
|
|
49
|
-
updatedAt: (0,
|
|
48
|
+
createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
49
|
+
updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
50
50
|
});
|
|
51
51
|
/**
|
|
52
52
|
* DDNS 域名池表
|
|
@@ -57,7 +57,7 @@ exports.ddnsDomains = (0, pg_core_1.pgTable)('identity_ddns_domain', {
|
|
|
57
57
|
status: (0, pg_core_1.text)('status').default('active'), // 'active' | 'suspended'
|
|
58
58
|
provider: (0, pg_core_1.text)('provider'), // 'cloudflare' | 'tencent'
|
|
59
59
|
zoneId: (0, pg_core_1.text)('zone_id'), // DNS Zone ID
|
|
60
|
-
createdAt: (0,
|
|
60
|
+
createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
61
61
|
});
|
|
62
62
|
/**
|
|
63
63
|
* DDNS 记录表
|
|
@@ -74,8 +74,8 @@ exports.ddnsRecords = (0, pg_core_1.pgTable)('identity_ddns_record', {
|
|
|
74
74
|
status: (0, pg_core_1.text)('status').default('active'), // 'active' | 'banned'
|
|
75
75
|
bannedReason: (0, pg_core_1.text)('banned_reason'),
|
|
76
76
|
ttl: (0, integer_1.integer)('ttl').default(60),
|
|
77
|
-
createdAt: (0,
|
|
78
|
-
updatedAt: (0,
|
|
77
|
+
createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
78
|
+
updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
79
79
|
});
|
|
80
80
|
exports.edgeNodes = (0, pg_core_1.pgTable)('identity_edge_node', {
|
|
81
81
|
id: (0, pg_core_1.text)('id').primaryKey(),
|
|
@@ -100,10 +100,10 @@ exports.edgeNodes = (0, pg_core_1.pgTable)('identity_edge_node', {
|
|
|
100
100
|
capabilities: (0, pg_core_1.text)('capabilities'), // JSON string: 能力列表
|
|
101
101
|
metadata: (0, pg_core_1.text)('metadata'), // JSON string: 复杂对象 (tunnel, certificate, metrics)
|
|
102
102
|
connectivityStatus: (0, pg_core_1.text)('connectivity_status').default('unknown'),
|
|
103
|
-
lastConnectivityCheck: (0,
|
|
104
|
-
createdAt: (0,
|
|
105
|
-
updatedAt: (0,
|
|
106
|
-
lastSeen: (0,
|
|
103
|
+
lastConnectivityCheck: (0, pg_core_1.timestamp)('last_connectivity_check', { withTimezone: true, mode: 'date' }),
|
|
104
|
+
createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
105
|
+
updatedAt: (0, pg_core_1.timestamp)('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
106
|
+
lastSeen: (0, pg_core_1.timestamp)('last_seen', { withTimezone: true, mode: 'date' }),
|
|
107
107
|
});
|
|
108
108
|
exports.edgeNodePods = (0, pg_core_1.pgTable)('identity_edge_node_pod', {
|
|
109
109
|
nodeId: (0, pg_core_1.text)('node_id').notNull().references(() => exports.edgeNodes.id, { onDelete: 'cascade' }),
|
|
@@ -114,7 +114,7 @@ exports.apiClientCredentials = (0, pg_core_1.pgTable)('identity_api_client_crede
|
|
|
114
114
|
webId: (0, pg_core_1.text)('web_id').notNull(),
|
|
115
115
|
accountId: (0, pg_core_1.text)('account_id').notNull(),
|
|
116
116
|
displayName: (0, pg_core_1.text)('display_name'),
|
|
117
|
-
createdAt: (0,
|
|
117
|
+
createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
118
118
|
});
|
|
119
119
|
/**
|
|
120
120
|
* Service Token 表
|
|
@@ -126,7 +126,7 @@ exports.serviceTokens = (0, pg_core_1.pgTable)('identity_service_token', {
|
|
|
126
126
|
serviceType: (0, pg_core_1.text)('service_type').notNull(), // 'local' | 'business' | 'cloud' | 'compute'
|
|
127
127
|
serviceId: (0, pg_core_1.text)('service_id').notNull(),
|
|
128
128
|
scopes: (0, pg_core_1.text)('scopes').notNull(), // JSON array: ["quota:write","usage:read"]
|
|
129
|
-
createdAt: (0,
|
|
130
|
-
expiresAt: (0,
|
|
129
|
+
createdAt: (0, pg_core_1.timestamp)('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),
|
|
130
|
+
expiresAt: (0, pg_core_1.timestamp)('expires_at', { withTimezone: true, mode: 'date' }),
|
|
131
131
|
});
|
|
132
132
|
//# sourceMappingURL=schema.pg.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.pg.js","sourceRoot":"","sources":["../../../src/identity/drizzle/schema.pg.ts"],"names":[],"mappings":"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","sourcesContent":["import { pgTable, text } from 'drizzle-orm/pg-core';\nimport { bigint as pgBigint } from 'drizzle-orm/pg-core/columns/bigint';\nimport { integer } from 'drizzle-orm/pg-core/columns/integer';\n\nexport const accountUsage = pgTable('identity_account_usage', {\n accountId: text('account_id').primaryKey(),\n storageBytes: pgBigint('storage_bytes', { mode: 'number' }).notNull().default(0),\n ingressBytes: pgBigint('ingress_bytes', { mode: 'number' }).notNull().default(0),\n egressBytes: pgBigint('egress_bytes', { mode: 'number' }).notNull().default(0),\n storageLimitBytes: pgBigint('storage_limit_bytes', { mode: 'number' }),\n bandwidthLimitBps: pgBigint('bandwidth_limit_bps', { mode: 'number' }),\n computeSeconds: pgBigint('compute_seconds', { mode: 'number' }).notNull().default(0),\n tokensUsed: pgBigint('tokens_used', { mode: 'number' }).notNull().default(0),\n computeLimitSeconds: pgBigint('compute_limit_seconds', { mode: 'number' }),\n tokenLimitMonthly: pgBigint('token_limit_monthly', { mode: 'number' }),\n periodStart: pgBigint('period_start', { mode: 'number' }),\n updatedAt: pgBigint('updated_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\nexport const podUsage = pgTable('identity_pod_usage', {\n podId: text('pod_id').primaryKey(),\n accountId: text('account_id').notNull(),\n storageBytes: pgBigint('storage_bytes', { mode: 'number' }).notNull().default(0),\n ingressBytes: pgBigint('ingress_bytes', { mode: 'number' }).notNull().default(0),\n egressBytes: pgBigint('egress_bytes', { mode: 'number' }).notNull().default(0),\n storageLimitBytes: pgBigint('storage_limit_bytes', { mode: 'number' }),\n bandwidthLimitBps: pgBigint('bandwidth_limit_bps', { mode: 'number' }),\n computeSeconds: pgBigint('compute_seconds', { mode: 'number' }).notNull().default(0),\n tokensUsed: pgBigint('tokens_used', { mode: 'number' }).notNull().default(0),\n computeLimitSeconds: pgBigint('compute_limit_seconds', { mode: 'number' }),\n tokenLimitMonthly: pgBigint('token_limit_monthly', { mode: 'number' }),\n periodStart: pgBigint('period_start', { mode: 'number' }),\n updatedAt: pgBigint('updated_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\n/**\n * WebID Profile 托管表\n * 用于身份与存储分离架构,Cloud 托管用户的 WebID Profile\n */\nexport const webidProfiles = pgTable('identity_webid_profile', {\n username: text('username').primaryKey(),\n webidUrl: text('webid_url').notNull(), // https://id.undefineds.co/alice/profile/card#me\n storageUrl: text('storage_url'), // https://alice.undefineds.xyz/ 或 https://pods.undefineds.co/alice/\n storageMode: text('storage_mode').default('cloud'), // 'cloud' | 'local' | 'custom'\n oidcIssuer: text('oidc_issuer'), // https://id.undefineds.co/\n profileData: text('profile_data'), // WebID Profile 的 JSON-LD 表示 (stored as JSON string)\n accountId: text('account_id'), // 关联的 CSS 账户 ID\n createdAt: pgBigint('created_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n updatedAt: pgBigint('updated_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\n/**\n * DDNS 域名池表\n * 管理可用的 DDNS 域名\n */\nexport const ddnsDomains = pgTable('identity_ddns_domain', {\n domain: text('domain').primaryKey(), // undefineds.xyz\n status: text('status').default('active'), // 'active' | 'suspended'\n provider: text('provider'), // 'cloudflare' | 'tencent'\n zoneId: text('zone_id'), // DNS Zone ID\n createdAt: pgBigint('created_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\n/**\n * DDNS 记录表\n * 已分配的子域名记录\n */\nexport const ddnsRecords = pgTable('identity_ddns_record', {\n subdomain: text('subdomain').primaryKey(), // alice\n domain: text('domain').notNull(), // undefineds.xyz\n ipAddress: text('ip_address'),\n ipv6Address: text('ipv6_address'),\n recordType: text('record_type').default('A'), // 'A' | 'AAAA'\n nodeId: text('node_id'), // 关联的节点 ID\n username: text('username'), // 关联的用户名\n status: text('status').default('active'), // 'active' | 'banned'\n bannedReason: text('banned_reason'),\n ttl: integer('ttl').default(60),\n createdAt: pgBigint('created_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n updatedAt: pgBigint('updated_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\nexport const edgeNodes = pgTable('identity_edge_node', {\n id: text('id').primaryKey(),\n ownerAccountId: text('owner_account_id'), // Owner of the node\n displayName: text('display_name'),\n tokenHash: text('token_hash').notNull(),\n nodeType: text('node_type').default('edge'), // 'center' | 'edge' | 'sp'\n subdomain: text('subdomain').unique(),\n accessMode: text('access_mode'),\n ipv4: text('ipv4'), // IPv4 地址\n publicPort: pgBigint('public_port', { mode: 'number' }),\n publicUrl: text('public_url'), // SP 的公网地址 (e.g. https://sp.example)\n serviceTokenHash: text('service_token_hash'), // Cloud → SP 回调认证 token (明文)\n provisionCodeHash: text('provision_code_hash'), // bind 时用户传入的配对码 (hash)\n internalIp: text('internal_ip'), // Internal network IP\n internalPort: pgBigint('internal_port', { mode: 'number' }),\n // Extracted from metadata\n hostname: text('hostname'), // 节点主机名\n ipv6: text('ipv6'), // IPv6 地址\n version: text('version'), // Agent 版本\n // JSON fields\n capabilities: text('capabilities'), // JSON string: 能力列表\n metadata: text('metadata'), // JSON string: 复杂对象 (tunnel, certificate, metrics)\n connectivityStatus: text('connectivity_status').default('unknown'),\n lastConnectivityCheck: pgBigint('last_connectivity_check', { mode: 'number' }),\n createdAt: pgBigint('created_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n updatedAt: pgBigint('updated_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n lastSeen: pgBigint('last_seen', { mode: 'number' }),\n});\n\nexport const edgeNodePods = pgTable('identity_edge_node_pod', {\n nodeId: text('node_id').notNull().references(() => edgeNodes.id, { onDelete: 'cascade' }),\n baseUrl: text('base_url').notNull(),\n});\n\nexport const apiClientCredentials = pgTable('identity_api_client_credentials', {\n clientId: text('client_id').primaryKey(),\n webId: text('web_id').notNull(),\n accountId: text('account_id').notNull(),\n displayName: text('display_name'),\n createdAt: pgBigint('created_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n});\n\n/**\n * Service Token 表\n * 用于服务间认证 (Business, Local SP, Cloud, Compute)\n */\nexport const serviceTokens = pgTable('identity_service_token', {\n id: text('id').primaryKey(),\n tokenHash: text('token_hash').notNull().unique(),\n serviceType: text('service_type').notNull(), // 'local' | 'business' | 'cloud' | 'compute'\n serviceId: text('service_id').notNull(),\n scopes: text('scopes').notNull(), // JSON array: [\"quota:write\",\"usage:read\"]\n createdAt: pgBigint('created_at', { mode: 'number' }).notNull().$defaultFn(() => Math.floor(Date.now() / 1000)),\n expiresAt: pgBigint('expires_at', { mode: 'number' }),\n});\n"]}
|
|
1
|
+
{"version":3,"file":"schema.pg.js","sourceRoot":"","sources":["../../../src/identity/drizzle/schema.pg.ts"],"names":[],"mappings":"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","sourcesContent":["import { pgTable, text, timestamp } from 'drizzle-orm/pg-core';\nimport { bigint as pgBigint } from 'drizzle-orm/pg-core/columns/bigint';\nimport { integer } from 'drizzle-orm/pg-core/columns/integer';\n\nexport const accountUsage = pgTable('identity_account_usage', {\n accountId: text('account_id').primaryKey(),\n storageBytes: pgBigint('storage_bytes', { mode: 'number' }).notNull().default(0),\n ingressBytes: pgBigint('ingress_bytes', { mode: 'number' }).notNull().default(0),\n egressBytes: pgBigint('egress_bytes', { mode: 'number' }).notNull().default(0),\n storageLimitBytes: pgBigint('storage_limit_bytes', { mode: 'number' }),\n bandwidthLimitBps: pgBigint('bandwidth_limit_bps', { mode: 'number' }),\n computeSeconds: pgBigint('compute_seconds', { mode: 'number' }).notNull().default(0),\n tokensUsed: pgBigint('tokens_used', { mode: 'number' }).notNull().default(0),\n computeLimitSeconds: pgBigint('compute_limit_seconds', { mode: 'number' }),\n tokenLimitMonthly: pgBigint('token_limit_monthly', { mode: 'number' }),\n periodStart: timestamp('period_start', { withTimezone: true, mode: 'date' }),\n updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n});\n\nexport const podUsage = pgTable('identity_pod_usage', {\n podId: text('pod_id').primaryKey(),\n accountId: text('account_id').notNull(),\n storageBytes: pgBigint('storage_bytes', { mode: 'number' }).notNull().default(0),\n ingressBytes: pgBigint('ingress_bytes', { mode: 'number' }).notNull().default(0),\n egressBytes: pgBigint('egress_bytes', { mode: 'number' }).notNull().default(0),\n storageLimitBytes: pgBigint('storage_limit_bytes', { mode: 'number' }),\n bandwidthLimitBps: pgBigint('bandwidth_limit_bps', { mode: 'number' }),\n computeSeconds: pgBigint('compute_seconds', { mode: 'number' }).notNull().default(0),\n tokensUsed: pgBigint('tokens_used', { mode: 'number' }).notNull().default(0),\n computeLimitSeconds: pgBigint('compute_limit_seconds', { mode: 'number' }),\n tokenLimitMonthly: pgBigint('token_limit_monthly', { mode: 'number' }),\n periodStart: timestamp('period_start', { withTimezone: true, mode: 'date' }),\n updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n});\n\n/**\n * WebID Profile 托管表\n * 用于身份与存储分离架构,Cloud 托管用户的 WebID Profile\n */\nexport const webidProfiles = pgTable('identity_webid_profile', {\n username: text('username').primaryKey(),\n webidUrl: text('webid_url').notNull(), // https://id.undefineds.co/alice/profile/card#me\n storageUrl: text('storage_url'), // https://alice.undefineds.xyz/ 或 https://pods.undefineds.co/alice/\n storageMode: text('storage_mode').default('cloud'), // 'cloud' | 'local' | 'custom'\n oidcIssuer: text('oidc_issuer'), // https://id.undefineds.co/\n profileData: text('profile_data'), // WebID Profile 的 JSON-LD 表示 (stored as JSON string)\n accountId: text('account_id'), // 关联的 CSS 账户 ID\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n});\n\n/**\n * DDNS 域名池表\n * 管理可用的 DDNS 域名\n */\nexport const ddnsDomains = pgTable('identity_ddns_domain', {\n domain: text('domain').primaryKey(), // undefineds.xyz\n status: text('status').default('active'), // 'active' | 'suspended'\n provider: text('provider'), // 'cloudflare' | 'tencent'\n zoneId: text('zone_id'), // DNS Zone ID\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n});\n\n/**\n * DDNS 记录表\n * 已分配的子域名记录\n */\nexport const ddnsRecords = pgTable('identity_ddns_record', {\n subdomain: text('subdomain').primaryKey(), // alice\n domain: text('domain').notNull(), // undefineds.xyz\n ipAddress: text('ip_address'),\n ipv6Address: text('ipv6_address'),\n recordType: text('record_type').default('A'), // 'A' | 'AAAA'\n nodeId: text('node_id'), // 关联的节点 ID\n username: text('username'), // 关联的用户名\n status: text('status').default('active'), // 'active' | 'banned'\n bannedReason: text('banned_reason'),\n ttl: integer('ttl').default(60),\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n});\n\nexport const edgeNodes = pgTable('identity_edge_node', {\n id: text('id').primaryKey(),\n ownerAccountId: text('owner_account_id'), // Owner of the node\n displayName: text('display_name'),\n tokenHash: text('token_hash').notNull(),\n nodeType: text('node_type').default('edge'), // 'center' | 'edge' | 'sp'\n subdomain: text('subdomain').unique(),\n accessMode: text('access_mode'),\n ipv4: text('ipv4'), // IPv4 地址\n publicPort: pgBigint('public_port', { mode: 'number' }),\n publicUrl: text('public_url'), // SP 的公网地址 (e.g. https://sp.example)\n serviceTokenHash: text('service_token_hash'), // Cloud → SP 回调认证 token (明文)\n provisionCodeHash: text('provision_code_hash'), // bind 时用户传入的配对码 (hash)\n internalIp: text('internal_ip'), // Internal network IP\n internalPort: pgBigint('internal_port', { mode: 'number' }),\n // Extracted from metadata\n hostname: text('hostname'), // 节点主机名\n ipv6: text('ipv6'), // IPv6 地址\n version: text('version'), // Agent 版本\n // JSON fields\n capabilities: text('capabilities'), // JSON string: 能力列表\n metadata: text('metadata'), // JSON string: 复杂对象 (tunnel, certificate, metrics)\n connectivityStatus: text('connectivity_status').default('unknown'),\n lastConnectivityCheck: timestamp('last_connectivity_check', { withTimezone: true, mode: 'date' }),\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n lastSeen: timestamp('last_seen', { withTimezone: true, mode: 'date' }),\n});\n\nexport const edgeNodePods = pgTable('identity_edge_node_pod', {\n nodeId: text('node_id').notNull().references(() => edgeNodes.id, { onDelete: 'cascade' }),\n baseUrl: text('base_url').notNull(),\n});\n\nexport const apiClientCredentials = pgTable('identity_api_client_credentials', {\n clientId: text('client_id').primaryKey(),\n webId: text('web_id').notNull(),\n accountId: text('account_id').notNull(),\n displayName: text('display_name'),\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n});\n\n/**\n * Service Token 表\n * 用于服务间认证 (Business, Local SP, Cloud, Compute)\n */\nexport const serviceTokens = pgTable('identity_service_token', {\n id: text('id').primaryKey(),\n tokenHash: text('token_hash').notNull().unique(),\n serviceType: text('service_type').notNull(), // 'local' | 'business' | 'cloud' | 'compute'\n serviceId: text('service_id').notNull(),\n scopes: text('scopes').notNull(), // JSON array: [\"quota:write\",\"usage:read\"]\n createdAt: timestamp('created_at', { withTimezone: true, mode: 'date' }).notNull().defaultNow(),\n expiresAt: timestamp('expires_at', { withTimezone: true, mode: 'date' }),\n});\n"]}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* 任务存储在 Pod 的 /tasks/{YYYY-MM-DD}.ttl 中,按天分片
|
|
7
7
|
*/
|
|
8
|
-
import type { SolidDatabase } from 'drizzle-solid';
|
|
8
|
+
import type { SolidDatabase } from '@undefineds.co/drizzle-solid';
|
|
9
9
|
import { Task as taskTable } from './schema';
|
|
10
10
|
import type { Task, TaskStatus, CreateTaskInput, TaskQueue, TaskQueueStats, ListTasksOptions } from './types';
|
|
11
11
|
export interface DrizzleTaskQueueOptions {
|
|
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.DrizzleTaskQueue = void 0;
|
|
11
11
|
const global_logger_factory_1 = require("global-logger-factory");
|
|
12
12
|
const crypto_1 = require("crypto");
|
|
13
|
-
const drizzle_solid_1 = require("drizzle-solid");
|
|
13
|
+
const drizzle_solid_1 = require("@undefineds.co/drizzle-solid");
|
|
14
14
|
const schema_1 = require("./schema");
|
|
15
15
|
/**
|
|
16
16
|
* 基于 drizzle-solid 的任务队列实现
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrizzleTaskQueue.js","sourceRoot":"","sources":["../../src/task/DrizzleTaskQueue.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * DrizzleTaskQueue - 基于 drizzle-solid 的任务队列\n *\n * 简化模型:消息 + Agent\n *\n * 任务存储在 Pod 的 /tasks/{YYYY-MM-DD}.ttl 中,按天分片\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\nimport { randomBytes } from 'crypto';\nimport { eq } from 'drizzle-solid';\nimport type { SolidDatabase } from 'drizzle-solid';\n\nimport { Task as taskTable, TaskStatus as TaskStatusConst } from './schema';\nimport type {\n Task,\n TaskStatus,\n CreateTaskInput,\n TaskQueue,\n TaskQueueStats,\n ListTasksOptions,\n} from './types';\n\nexport interface DrizzleTaskQueueOptions {\n /**\n * Pod base URL\n */\n podBaseUrl: string;\n /**\n * drizzle-solid 数据库实例\n */\n db: SolidDatabase<{ task: typeof taskTable }>;\n}\n\n/**\n * 基于 drizzle-solid 的任务队列实现\n */\nexport class DrizzleTaskQueue implements TaskQueue {\n protected readonly logger = getLoggerFor(this);\n private readonly podBaseUrl: string;\n private readonly db: SolidDatabase<{ task: typeof taskTable }>;\n\n public constructor(options: DrizzleTaskQueueOptions) {\n this.podBaseUrl = options.podBaseUrl.endsWith('/') ? options.podBaseUrl : `${options.podBaseUrl}/`;\n this.db = options.db;\n }\n\n /**\n * 创建任务\n */\n public async createTask(input: CreateTaskInput): Promise<Task> {\n const id = this.generateTaskId();\n const now = new Date();\n\n const taskData = {\n id,\n agent: input.agent,\n message: input.message,\n status: TaskStatusConst.PENDING,\n createdAt: now,\n };\n\n await this.db.insert(taskTable).values(taskData);\n\n this.logger.info(`Created task ${id} for agent \"${input.agent}\"`);\n\n return {\n id,\n agent: input.agent,\n message: input.message,\n status: 'pending',\n createdAt: now,\n };\n }\n\n /**\n * 获取任务\n */\n public async getTask(taskId: string): Promise<Task | null> {\n const tasks = await this.db.select().from(taskTable).where(eq(taskTable.id, taskId));\n\n if (tasks.length === 0) {\n return null;\n }\n\n return this.dbTaskToTask(tasks[0]);\n }\n\n /**\n * 获取任务列表\n */\n public async listTasks(options?: ListTasksOptions): Promise<Task[]> {\n let query = this.db.select().from(taskTable);\n\n // 状态过滤\n if (options?.status) {\n query = query.where(eq(taskTable.status, options.status));\n }\n\n const tasks = await query;\n\n // 转换为 Task 接口\n let result = tasks.map((t: Record<string, unknown>) => this.dbTaskToTask(t));\n\n // Agent 过滤\n if (options?.agent) {\n result = result.filter((t: Task) => t.agent === options.agent);\n }\n\n // 排序\n if (options?.orderBy) {\n const order = options.order === 'asc' ? 1 : -1;\n result.sort((a: Task, b: Task) => {\n const aVal = a[options.orderBy!];\n const bVal = b[options.orderBy!];\n if (aVal instanceof Date && bVal instanceof Date) {\n return (aVal.getTime() - bVal.getTime()) * order;\n }\n return 0;\n });\n }\n\n // 分页\n const offset = options?.offset ?? 0;\n const limit = options?.limit ?? result.length;\n return result.slice(offset, offset + limit);\n }\n\n /**\n * 更新任务状态\n */\n public async updateTaskStatus(\n taskId: string,\n status: TaskStatus,\n updates?: Partial<Task>,\n ): Promise<void> {\n const now = new Date();\n\n const updateData: Record<string, unknown> = {\n status,\n };\n\n // 根据状态设置时间字段\n if (status === 'running') {\n updateData.startedAt = now;\n } else if (status === 'completed' || status === 'failed') {\n updateData.completedAt = now;\n }\n\n // 合并其他更新\n if (updates) {\n if (updates.result !== undefined) updateData.result = updates.result;\n if (updates.error !== undefined) updateData.error = updates.error;\n }\n\n await this.db.update(taskTable).set(updateData).where(eq(taskTable.id, taskId));\n\n this.logger.info(`Task ${taskId} status changed to ${status}`);\n }\n\n /**\n * 删除任务\n */\n public async deleteTask(taskId: string): Promise<void> {\n await this.db.delete(taskTable).where(eq(taskTable.id, taskId));\n this.logger.info(`Deleted task ${taskId}`);\n }\n\n /**\n * 获取队列统计\n */\n public async getStats(): Promise<TaskQueueStats> {\n const tasks = await this.db.select().from(taskTable);\n\n const stats: TaskQueueStats = {\n pending: 0,\n running: 0,\n completed: 0,\n failed: 0,\n total: tasks.length,\n byAgent: {},\n };\n\n for (const task of tasks) {\n const taskRecord = task as Record<string, unknown>;\n const status = (taskRecord.status as TaskStatus) ?? 'pending';\n stats[status]++;\n\n // 按 Agent 统计\n const agent = taskRecord.agent as string ?? 'unknown';\n stats.byAgent[agent] = (stats.byAgent[agent] ?? 0) + 1;\n }\n\n return stats;\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private generateTaskId(): string {\n const timestamp = Date.now().toString(36);\n const random = randomBytes(4).toString('hex');\n return `task-${timestamp}-${random}`;\n }\n\n /**\n * 将数据库记录转换为 Task 接口\n */\n private dbTaskToTask(dbTask: Record<string, unknown>): Task {\n return {\n id: dbTask.id as string,\n agent: dbTask.agent as string,\n message: dbTask.message as string,\n status: (dbTask.status as TaskStatus) ?? 'pending',\n createdAt: dbTask.createdAt as Date,\n startedAt: dbTask.startedAt as Date | undefined,\n completedAt: dbTask.completedAt as Date | undefined,\n result: dbTask.result as unknown,\n error: dbTask.error as string | undefined,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DrizzleTaskQueue.js","sourceRoot":"","sources":["../../src/task/DrizzleTaskQueue.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * DrizzleTaskQueue - 基于 drizzle-solid 的任务队列\n *\n * 简化模型:消息 + Agent\n *\n * 任务存储在 Pod 的 /tasks/{YYYY-MM-DD}.ttl 中,按天分片\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\nimport { randomBytes } from 'crypto';\nimport { eq } from '@undefineds.co/drizzle-solid';\nimport type { SolidDatabase } from '@undefineds.co/drizzle-solid';\n\nimport { Task as taskTable, TaskStatus as TaskStatusConst } from './schema';\nimport type {\n Task,\n TaskStatus,\n CreateTaskInput,\n TaskQueue,\n TaskQueueStats,\n ListTasksOptions,\n} from './types';\n\nexport interface DrizzleTaskQueueOptions {\n /**\n * Pod base URL\n */\n podBaseUrl: string;\n /**\n * drizzle-solid 数据库实例\n */\n db: SolidDatabase<{ task: typeof taskTable }>;\n}\n\n/**\n * 基于 drizzle-solid 的任务队列实现\n */\nexport class DrizzleTaskQueue implements TaskQueue {\n protected readonly logger = getLoggerFor(this);\n private readonly podBaseUrl: string;\n private readonly db: SolidDatabase<{ task: typeof taskTable }>;\n\n public constructor(options: DrizzleTaskQueueOptions) {\n this.podBaseUrl = options.podBaseUrl.endsWith('/') ? options.podBaseUrl : `${options.podBaseUrl}/`;\n this.db = options.db;\n }\n\n /**\n * 创建任务\n */\n public async createTask(input: CreateTaskInput): Promise<Task> {\n const id = this.generateTaskId();\n const now = new Date();\n\n const taskData = {\n id,\n agent: input.agent,\n message: input.message,\n status: TaskStatusConst.PENDING,\n createdAt: now,\n };\n\n await this.db.insert(taskTable).values(taskData);\n\n this.logger.info(`Created task ${id} for agent \"${input.agent}\"`);\n\n return {\n id,\n agent: input.agent,\n message: input.message,\n status: 'pending',\n createdAt: now,\n };\n }\n\n /**\n * 获取任务\n */\n public async getTask(taskId: string): Promise<Task | null> {\n const tasks = await this.db.select().from(taskTable).where(eq(taskTable.id, taskId));\n\n if (tasks.length === 0) {\n return null;\n }\n\n return this.dbTaskToTask(tasks[0]);\n }\n\n /**\n * 获取任务列表\n */\n public async listTasks(options?: ListTasksOptions): Promise<Task[]> {\n let query = this.db.select().from(taskTable);\n\n // 状态过滤\n if (options?.status) {\n query = query.where(eq(taskTable.status, options.status));\n }\n\n const tasks = await query;\n\n // 转换为 Task 接口\n let result = tasks.map((t: Record<string, unknown>) => this.dbTaskToTask(t));\n\n // Agent 过滤\n if (options?.agent) {\n result = result.filter((t: Task) => t.agent === options.agent);\n }\n\n // 排序\n if (options?.orderBy) {\n const order = options.order === 'asc' ? 1 : -1;\n result.sort((a: Task, b: Task) => {\n const aVal = a[options.orderBy!];\n const bVal = b[options.orderBy!];\n if (aVal instanceof Date && bVal instanceof Date) {\n return (aVal.getTime() - bVal.getTime()) * order;\n }\n return 0;\n });\n }\n\n // 分页\n const offset = options?.offset ?? 0;\n const limit = options?.limit ?? result.length;\n return result.slice(offset, offset + limit);\n }\n\n /**\n * 更新任务状态\n */\n public async updateTaskStatus(\n taskId: string,\n status: TaskStatus,\n updates?: Partial<Task>,\n ): Promise<void> {\n const now = new Date();\n\n const updateData: Record<string, unknown> = {\n status,\n };\n\n // 根据状态设置时间字段\n if (status === 'running') {\n updateData.startedAt = now;\n } else if (status === 'completed' || status === 'failed') {\n updateData.completedAt = now;\n }\n\n // 合并其他更新\n if (updates) {\n if (updates.result !== undefined) updateData.result = updates.result;\n if (updates.error !== undefined) updateData.error = updates.error;\n }\n\n await this.db.update(taskTable).set(updateData).where(eq(taskTable.id, taskId));\n\n this.logger.info(`Task ${taskId} status changed to ${status}`);\n }\n\n /**\n * 删除任务\n */\n public async deleteTask(taskId: string): Promise<void> {\n await this.db.delete(taskTable).where(eq(taskTable.id, taskId));\n this.logger.info(`Deleted task ${taskId}`);\n }\n\n /**\n * 获取队列统计\n */\n public async getStats(): Promise<TaskQueueStats> {\n const tasks = await this.db.select().from(taskTable);\n\n const stats: TaskQueueStats = {\n pending: 0,\n running: 0,\n completed: 0,\n failed: 0,\n total: tasks.length,\n byAgent: {},\n };\n\n for (const task of tasks) {\n const taskRecord = task as Record<string, unknown>;\n const status = (taskRecord.status as TaskStatus) ?? 'pending';\n stats[status]++;\n\n // 按 Agent 统计\n const agent = taskRecord.agent as string ?? 'unknown';\n stats.byAgent[agent] = (stats.byAgent[agent] ?? 0) + 1;\n }\n\n return stats;\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private generateTaskId(): string {\n const timestamp = Date.now().toString(36);\n const random = randomBytes(4).toString('hex');\n return `task-${timestamp}-${random}`;\n }\n\n /**\n * 将数据库记录转换为 Task 接口\n */\n private dbTaskToTask(dbTask: Record<string, unknown>): Task {\n return {\n id: dbTask.id as string,\n agent: dbTask.agent as string,\n message: dbTask.message as string,\n status: (dbTask.status as TaskStatus) ?? 'pending',\n createdAt: dbTask.createdAt as Date,\n startedAt: dbTask.startedAt as Date | undefined,\n completedAt: dbTask.completedAt as Date | undefined,\n result: dbTask.result as unknown,\n error: dbTask.error as string | undefined,\n };\n }\n}\n"]}
|
package/dist/task/schema.d.ts
CHANGED
|
@@ -32,16 +32,16 @@ export type TaskStatusType = (typeof TaskStatus)[keyof typeof TaskStatus];
|
|
|
32
32
|
* udfs:status "pending" ;
|
|
33
33
|
* udfs:createdAt "2026-01-09T10:00:00Z"^^xsd:dateTime .
|
|
34
34
|
*/
|
|
35
|
-
export declare const Task: import("drizzle-solid/dist/core/schema").PodTableWithColumns<import("drizzle-solid/dist/core/schema").ResolvedColumns<{
|
|
36
|
-
id: import("drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
37
|
-
agent: import("drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
38
|
-
message: import("drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
39
|
-
status: import("drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
40
|
-
createdAt: import("drizzle-solid/dist/core/schema").ColumnBuilder<"datetime", null, false, false>;
|
|
41
|
-
startedAt: import("drizzle-solid/dist/core/schema").ColumnBuilder<"datetime", null, false, false>;
|
|
42
|
-
completedAt: import("drizzle-solid/dist/core/schema").ColumnBuilder<"datetime", null, false, false>;
|
|
43
|
-
result: import("drizzle-solid/dist/core/schema").ColumnBuilder<"json", null, false, false>;
|
|
44
|
-
error: import("drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
35
|
+
export declare const Task: import("@undefineds.co/drizzle-solid/dist/core/schema").PodTableWithColumns<import("@undefineds.co/drizzle-solid/dist/core/schema").ResolvedColumns<{
|
|
36
|
+
id: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
37
|
+
agent: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
38
|
+
message: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
39
|
+
status: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
40
|
+
createdAt: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"datetime", null, false, false>;
|
|
41
|
+
startedAt: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"datetime", null, false, false>;
|
|
42
|
+
completedAt: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"datetime", null, false, false>;
|
|
43
|
+
result: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"json", null, false, false>;
|
|
44
|
+
error: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
45
45
|
}>>;
|
|
46
46
|
/**
|
|
47
47
|
* 获取今天的任务文件路径
|
package/dist/task/schema.js
CHANGED
|
@@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.Task = exports.TaskStatus = void 0;
|
|
16
16
|
exports.getTodayTaskPath = getTodayTaskPath;
|
|
17
17
|
exports.getTaskPathForDate = getTaskPathForDate;
|
|
18
|
-
const drizzle_solid_1 = require("drizzle-solid");
|
|
18
|
+
const drizzle_solid_1 = require("@undefineds.co/drizzle-solid");
|
|
19
19
|
const vocab_1 = require("../vocab");
|
|
20
20
|
/**
|
|
21
21
|
* 任务状态
|