@downcity/services 0.1.73 → 0.1.83

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.
@@ -194,8 +194,8 @@ export declare class AccountsService extends InstallableService {
194
194
  }, {}, {
195
195
  length: number | undefined;
196
196
  }>;
197
- town_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
198
- name: "town_id";
197
+ city_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
198
+ name: "city_id";
199
199
  tableName: "service_accounts_oauth_states";
200
200
  dataType: "string";
201
201
  columnType: "SQLiteText";
@@ -41,7 +41,7 @@ export class AccountsService extends InstallableService {
41
41
  this.options = options;
42
42
  this.instruction = ({ actions }) => [
43
43
  "提供 Downcity 的账号、邮箱验证、GitHub/Google/WeChat OAuth 登录能力。",
44
- "注册或登录时传入 town_id 后,接口会返回绑定该 town 的 City user_token。",
44
+ "注册或登录时传入 city_id 后,接口会返回绑定该 city 的 City user_token。",
45
45
  "OAuth 回调地址固定为 /v1/accounts/oauth/callback,服务会根据 City 公网地址生成完整回调 URL。",
46
46
  `当前暴露 ${actions.length} 个动作,常用流程是 register/login -> verify-email 或 oauth/start -> me。`,
47
47
  ].join("\n");
@@ -159,7 +159,7 @@ export class AccountsService extends InstallableService {
159
159
  });
160
160
  }
161
161
  const userToken = await ctx.createUserToken({
162
- town_id: String(body.town_id ?? ""),
162
+ city_id: String(body.city_id ?? ""),
163
163
  user_id,
164
164
  ttl: this.options.token_ttl,
165
165
  });
@@ -201,7 +201,7 @@ export class AccountsService extends InstallableService {
201
201
  });
202
202
  }
203
203
  const userToken = await ctx.createUserToken({
204
- town_id: String(body.town_id ?? ""),
204
+ city_id: String(body.city_id ?? ""),
205
205
  user_id,
206
206
  ttl: this.options.token_ttl,
207
207
  });
@@ -236,9 +236,9 @@ export class AccountsService extends InstallableService {
236
236
  if (!config) {
237
237
  return c.jsonResponse({ error: "provider not configured" }, 400);
238
238
  }
239
- const town_id = String(body.town_id ?? "").trim() || "town_downcity";
239
+ const city_id = String(body.city_id ?? "").trim() || "city_downcity";
240
240
  const state = randomToken(24);
241
- await this.createOAuthState(town_id, provider, state);
241
+ await this.createOAuthState(city_id, provider, state);
242
242
  const url = buildOAuthAuthorizeURL(config, this.getOAuthCallbackURL(), state);
243
243
  return c.jsonResponse({ url, state, provider });
244
244
  },
@@ -337,7 +337,7 @@ export class AccountsService extends InstallableService {
337
337
  const profile = await resolveOAuthProfile(provider, this.getOAuthProviderConfig(provider), code, this.getOAuthCallbackURL());
338
338
  const authUserId = await this.ensureOAuthAuthUser(profile, request);
339
339
  const result = await this._authenticator.createToken({
340
- town_id: entry.town_id,
340
+ city_id: entry.city_id,
341
341
  user_id: authUserId,
342
342
  ttl: this.options.token_ttl,
343
343
  });
@@ -468,14 +468,14 @@ export class AccountsService extends InstallableService {
468
468
  /**
469
469
  * 创建 OAuth state。
470
470
  */
471
- async createOAuthState(town_id, provider, state) {
472
- await runPrepared(this.rawPrepare(`INSERT INTO ${ACCOUNTS_OAUTH_STATE_TABLE} (state, town_id, provider, user_token, created_at) VALUES (?, ?, ?, ?, ?)`), [state, town_id, provider, "", Date.now()]);
471
+ async createOAuthState(city_id, provider, state) {
472
+ await runPrepared(this.rawPrepare(`INSERT INTO ${ACCOUNTS_OAUTH_STATE_TABLE} (state, city_id, provider, user_token, created_at) VALUES (?, ?, ?, ?, ?)`), [state, city_id, provider, "", Date.now()]);
473
473
  }
474
474
  /**
475
475
  * 读取 OAuth state。
476
476
  */
477
477
  async readOAuthState(state) {
478
- const row = await readPreparedFirst(this.rawPrepare(`SELECT state, town_id, provider, user_token, created_at FROM ${ACCOUNTS_OAUTH_STATE_TABLE} WHERE state = ?`), [state]);
478
+ const row = await readPreparedFirst(this.rawPrepare(`SELECT state, city_id, provider, user_token, created_at FROM ${ACCOUNTS_OAUTH_STATE_TABLE} WHERE state = ?`), [state]);
479
479
  if (!row)
480
480
  return null;
481
481
  if (Date.now() - Number(row.created_at) > OAUTH_STATE_TTL_MS) {
@@ -73,9 +73,9 @@ export interface AccountsOAuthStateRow extends Record<string, unknown> {
73
73
  */
74
74
  state: string;
75
75
  /**
76
- * 登录成功后要签发到哪个 town
76
+ * 登录成功后要签发到哪个 city
77
77
  */
78
- town_id: string;
78
+ city_id: string;
79
79
  /**
80
80
  * 第三方 provider 标识。
81
81
  */
@@ -255,8 +255,8 @@ export declare const accountsOAuthStates: import("drizzle-orm/sqlite-core").SQLi
255
255
  }, {}, {
256
256
  length: number | undefined;
257
257
  }>;
258
- town_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
259
- name: "town_id";
258
+ city_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
259
+ name: "city_id";
260
260
  tableName: "service_accounts_oauth_states";
261
261
  dataType: "string";
262
262
  columnType: "SQLiteText";
@@ -69,9 +69,9 @@ export const accountsOAuthStates = sqliteTable(ACCOUNTS_OAUTH_STATE_TABLE, {
69
69
  */
70
70
  state: text("state").primaryKey(),
71
71
  /**
72
- * 登录成功后要签发到哪个 town
72
+ * 登录成功后要签发到哪个 city
73
73
  */
74
- town_id: text("town_id").notNull(),
74
+ city_id: text("city_id").notNull(),
75
75
  /**
76
76
  * provider 标识。
77
77
  */
@@ -2,7 +2,7 @@
2
2
  * Downcity 官方 Balance 服务实现。
3
3
  *
4
4
  * 设计边界:
5
- * - 余额是用户级全局钱包,不与 town 绑定
5
+ * - 余额是用户级全局钱包,不与 city 绑定
6
6
  * - 服务只负责账户、流水、充值单、redeem_code 与原子加减款
7
7
  * - 真正的计费策略应由业务方在 hook 中直接调用本服务
8
8
  */
@@ -2,7 +2,7 @@
2
2
  * Downcity 官方 Balance 服务实现。
3
3
  *
4
4
  * 设计边界:
5
- * - 余额是用户级全局钱包,不与 town 绑定
5
+ * - 余额是用户级全局钱包,不与 city 绑定
6
6
  * - 服务只负责账户、流水、充值单、redeem_code 与原子加减款
7
7
  * - 真正的计费策略应由业务方在 hook 中直接调用本服务
8
8
  */
@@ -42,8 +42,8 @@ export declare const usageEvents: import("drizzle-orm/sqlite-core").SQLiteTableW
42
42
  }, {}, {
43
43
  length: number | undefined;
44
44
  }>;
45
- town_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
46
- name: "town_id";
45
+ city_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
46
+ name: "city_id";
47
47
  tableName: "service_usage_events";
48
48
  dataType: "string";
49
49
  columnType: "SQLiteText";
@@ -210,8 +210,8 @@ export declare class UsageService extends InstallableService {
210
210
  }, {}, {
211
211
  length: number | undefined;
212
212
  }>;
213
- town_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
214
- name: "town_id";
213
+ city_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
214
+ name: "city_id";
215
215
  tableName: "service_usage_events";
216
216
  dataType: "string";
217
217
  columnType: "SQLiteText";
@@ -11,7 +11,7 @@ import { InstallableService } from "@downcity/city";
11
11
  */
12
12
  export const usageEvents = sqliteTable("service_usage_events", {
13
13
  event_id: text("event_id").primaryKey(),
14
- town_id: text("town_id").notNull(),
14
+ city_id: text("city_id").notNull(),
15
15
  user_id: text("user_id").notNull(),
16
16
  service: text("service").notNull(),
17
17
  model_id: text("model_id").notNull(),
@@ -77,7 +77,7 @@ export class UsageService extends InstallableService {
77
77
  return requestCtx.jsonResponse({
78
78
  items: await events.select({
79
79
  user_id: requestCtx.user?.user_id ?? "",
80
- town_id: requestCtx.town?.town_id ?? "",
80
+ city_id: requestCtx.city?.city_id ?? "",
81
81
  }),
82
82
  });
83
83
  },
@@ -87,11 +87,11 @@ export class UsageService extends InstallableService {
87
87
  /**
88
88
  * 只记录真实用户侧调用。
89
89
  *
90
- * 管理端操作没有 user/town 上下文,usage 服务自己的查询也不应反过来
90
+ * 管理端操作没有 user/city 上下文,usage 服务自己的查询也不应反过来
91
91
  * 产生 usage 事件,否则统计接口会污染自身结果。
92
92
  */
93
93
  function shouldRecordUsage(ctx) {
94
- return Boolean(ctx.user?.user_id && ctx.town?.town_id && ctx.service?.id !== "usage");
94
+ return Boolean(ctx.user?.user_id && ctx.city?.city_id && ctx.service?.id !== "usage");
95
95
  }
96
96
  /**
97
97
  * 创建 usage 事件记录。
@@ -99,7 +99,7 @@ function shouldRecordUsage(ctx) {
99
99
  function createUsageEvent(ctx, status) {
100
100
  return {
101
101
  event_id: `usage_${randomId()}`,
102
- town_id: ctx.town?.town_id ?? "",
102
+ city_id: ctx.city?.city_id ?? "",
103
103
  user_id: ctx.user?.user_id ?? "",
104
104
  service: ctx.service?.id ?? "",
105
105
  model_id: ctx.variant?.id ?? "",
@@ -119,12 +119,12 @@ function createUsageEvent(ctx, status) {
119
119
  function summarizeUsage(rows) {
120
120
  const byKey = new Map();
121
121
  for (const row of rows) {
122
- const key = `${row.town_id}\u0000${row.service}\u0000${row.status}`;
123
- const current = byKey.get(key) ?? { town_id: row.town_id, service: row.service, status: row.status, count: 0 };
122
+ const key = `${row.city_id}\u0000${row.service}\u0000${row.status}`;
123
+ const current = byKey.get(key) ?? { city_id: row.city_id, service: row.service, status: row.status, count: 0 };
124
124
  current.count += 1;
125
125
  byKey.set(key, current);
126
126
  }
127
- return [...byKey.values()].sort((a, b) => `${a.town_id}:${a.service}:${a.status}`.localeCompare(`${b.town_id}:${b.service}:${b.status}`));
127
+ return [...byKey.values()].sort((a, b) => `${a.city_id}:${a.service}:${a.status}`.localeCompare(`${b.city_id}:${b.service}:${b.status}`));
128
128
  }
129
129
  /**
130
130
  * 生成随机 ID(兼容 Node 和 Workers)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@downcity/services",
3
- "version": "0.1.73",
3
+ "version": "0.1.83",
4
4
  "description": "Downcity public services package for accounts, balance, usage, Stripe, Creem, Dodo, and Waffo payment flows.",
5
5
  "type": "module",
6
6
  "main": "./bin/index.js",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@waffo/pancake-ts": "^0.11.0",
53
- "@downcity/city": "0.2.82",
53
+ "@downcity/city": "0.2.92",
54
54
  "better-auth": "^1.6.12",
55
55
  "dodopayments": "^2.36.0",
56
56
  "drizzle-orm": "^0.45.2"