@xuda.io/account_module 1.2.2257 → 1.2.2259

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/index.mjs CHANGED
@@ -34,6 +34,7 @@ const account_info_properties = [
34
34
  'network_lang',
35
35
  'network_country_code',
36
36
  'network_city_slug',
37
+ 'public_profile_disabled',
37
38
  ];
38
39
 
39
40
  global._conf = (
@@ -579,42 +580,9 @@ export const increment_account_usage = async function (req) {
579
580
  // app type?".
580
581
  const BILLABLE_APP_TYPES = ['vps', 'datacenter', 'instance', 'balancer'];
581
582
 
582
- // Stamp `app_cost.terminated_ts` on an app doc IMMEDIATELY, without
583
- // waiting for the destroy job to pick up. Called from the dashboard
584
- // the instant the user confirms a destroy so the billing UI reacts
585
- // without delay.
586
- //
587
- // Why we need this: destroy_app runs with { job: true } — i.e. the
588
- // HTTP call queues a background job and returns right away. The job
589
- // worker eventually executes destroy_app server-side, which marks
590
- // terminated_ts at the START of its own execution. But during the
591
- // window between "request returns" and "job worker starts", the
592
- // app doc still looks billable. The dashboard refresh in that
593
- // window sees the old state — exactly the "GUI doesn't react /
594
- // second refresh fixes it" symptom.
595
- //
596
- // This endpoint sidesteps the job queue entirely. It's a synchronous
597
- // 2-line write — no DO API calls, no destroy chain. The dashboard
598
- // calls it BEFORE the destroy_app job, returns can render the new
599
- // billing state without waiting on infra teardown.
600
- //
601
- // Idempotent: if terminated_ts is already set, returns immediately.
602
- export const mark_app_terminated = async function (req) {
603
- const { app_id } = req || {};
604
- if (!app_id) return { code: -1, data: 'app_id required' };
605
- try {
606
- const ret = await db_module.get_couch_doc('xuda_master', app_id);
607
- if (ret.code < 0) return { code: -1, data: 'app not found' };
608
- const app_doc = ret.data;
609
- if (!app_doc.app_cost) return { code: 1, data: 'no app_cost — nothing to mark' };
610
- if (app_doc.app_cost.terminated_ts) return { code: 1, data: 'already terminated' };
611
- app_doc.app_cost.terminated_ts = Date.now();
612
- await db_module.save_couch_doc('xuda_master', app_doc);
613
- return { code: 1, data: { terminated_ts: app_doc.app_cost.terminated_ts } };
614
- } catch (err) {
615
- return { code: -1, data: err.message };
616
- }
617
- };
583
+ // `mark_app_terminated` was removed its job is now done by
584
+ // `pre_destroy_app` in app_module, wired up via http_module's
585
+ // pre_dispatch hook on `destroy_app`. See cpi/app_module/index.mjs.
618
586
 
619
587
  // -------------------------------------------------------------------
620
588
  // Abuse detection — see the "How can we detect abuse?" plan.
@@ -1022,8 +990,16 @@ export const get_account_data = async function (req) {
1022
990
  support_plan_changed: acc_obj.support_plan_changed,
1023
991
  ai_workspace_plan: acc_obj.ai_workspace_plan,
1024
992
  storage_plan_changed: acc_obj.storage_plan_changed,
993
+ account_hosted_email: acc_obj.account_hosted_email || null,
1025
994
  account_project_id: acc_obj.account_project_id,
1026
- is_boarded: acc_obj.isBoarded,
995
+ // Coerce to explicit boolean. New accounts have `isBoarded`
996
+ // undefined; without this, JSON serialization drops the field
997
+ // entirely. The dashboard's SAVE_user uses spread-merge which
998
+ // doesn't overwrite missing-from-response fields, so a stale
999
+ // `is_boarded: true` from a previous user's localStorage would
1000
+ // never get cleared. Always sending an explicit false keeps the
1001
+ // gate honest.
1002
+ is_boarded: !!acc_obj.isBoarded,
1027
1003
 
1028
1004
  prices_info: acc_obj.prices_info,
1029
1005
  activity_usage: acc_obj.activity_usage,
@@ -1092,6 +1068,52 @@ export const get_account_instances = async function (req) {
1092
1068
  key: req.uid,
1093
1069
  });
1094
1070
  };
1071
+ // Standalone VPS list for the sidenav — lets the dashboard refresh DATA.vps
1072
+ // after a deploy without a full account reload (SideNavData calls this). Same
1073
+ // user_vps view that the initial account load uses.
1074
+ export const get_account_vps = async function (req) {
1075
+ return await db_module.get_couch_view('xuda_master', 'user_vps', {
1076
+ key: req.uid,
1077
+ });
1078
+ };
1079
+
1080
+ // Advertising campaigns are apps (app_type:'advertising'). A Mango query by
1081
+ // owner avoids needing a dedicated CouchDB view; shaped like get_couch_view
1082
+ // ({code, data:{rows:[{id,value}]}}) so SideNavData buckets them into
1083
+ // DATA.advertising exactly like deployments/vps.
1084
+ export const get_account_advertising = async function (req) {
1085
+ try {
1086
+ // Superuser sees EVERY campaign across all accounts; everyone else only their own.
1087
+ const isSuper = _conf.superuser_account_ids?.includes(req.uid);
1088
+ const selector = isSuper ? { app_type: 'advertising', docType: 'app' } : { app_uId: req.uid, app_type: 'advertising', docType: 'app' };
1089
+ const ret = await db_module.find_couch_query('xuda_master', {
1090
+ selector,
1091
+ limit: 1000,
1092
+ });
1093
+ const rows = (ret?.docs || []).map((d) => ({ id: d._id, value: d }));
1094
+ return { code: 1, data: { rows } };
1095
+ } catch (err) {
1096
+ return { code: -1, data: err.message };
1097
+ }
1098
+ };
1099
+
1100
+ // Static websites are apps (app_type:'static_website') created via create_app, but
1101
+ // they aren't emitted by any user_* CouchDB view, so they never surface in a sidenav
1102
+ // bucket. Same Mango-query approach as get_account_advertising → DATA.static_website.
1103
+ export const get_account_static_websites = async function (req) {
1104
+ try {
1105
+ const isSuper = _conf.superuser_account_ids?.includes(req.uid);
1106
+ const selector = isSuper ? { app_type: 'static_website', docType: 'app' } : { app_uId: req.uid, app_type: 'static_website', docType: 'app' };
1107
+ const ret = await db_module.find_couch_query('xuda_master', {
1108
+ selector,
1109
+ limit: 1000,
1110
+ });
1111
+ const rows = (ret?.docs || []).map((d) => ({ id: d._id, value: d }));
1112
+ return { code: 1, data: { rows } };
1113
+ } catch (err) {
1114
+ return { code: -1, data: err.message };
1115
+ }
1116
+ };
1095
1117
 
1096
1118
  export const get_account_info = async function (req) {
1097
1119
  return await get_account_data({
@@ -1263,7 +1285,7 @@ export const get_account_name = async function (req) {
1263
1285
  if (data.code < 0) {
1264
1286
  return data;
1265
1287
  }
1266
- const { membership_plan = '', support_plan = '', ai_workspace_plan = '', date_created_ts = '' } = data.data;
1288
+ const { membership_plan = '', support_plan = '', ai_workspace_plan = '', date_created_ts = '', stat = '' } = data.data;
1267
1289
  var obj = {
1268
1290
  first_name: '',
1269
1291
  last_name: '',
@@ -1275,13 +1297,41 @@ export const get_account_name = async function (req) {
1275
1297
  support_plan,
1276
1298
  ai_workspace_plan,
1277
1299
  date_created_ts,
1300
+ stat,
1278
1301
  };
1279
1302
  if (data.data.account_info) {
1280
- const { first_name, last_name, email, phone_number, profile_picture, profile_avatar, username, website, country, bio, industry, account_type, address, city, state, zip, business_name, auto_respond, auto_respond_mode, auto_respond_agents, avatar_source, active_account_profile_id } =
1281
- data.data.account_info;
1303
+ const {
1304
+ first_name,
1305
+ last_name,
1306
+ email,
1307
+ phone_number,
1308
+ profile_picture,
1309
+ profile_avatar,
1310
+ username,
1311
+ website,
1312
+ country,
1313
+ bio,
1314
+ industry,
1315
+ account_type,
1316
+ address,
1317
+ city,
1318
+ state,
1319
+ zip,
1320
+ business_name,
1321
+ auto_respond,
1322
+ auto_respond_mode,
1323
+ auto_respond_agents,
1324
+ avatar_source,
1325
+ active_account_profile_id,
1326
+ network_country_code,
1327
+ public_profile_disabled,
1328
+ } = data.data.account_info;
1282
1329
 
1283
1330
  obj = {
1284
1331
  _id: data.data._id,
1332
+ stat,
1333
+ network_country_code,
1334
+ public_profile_disabled,
1285
1335
  first_name,
1286
1336
  last_name,
1287
1337
  email,
@@ -1364,6 +1414,11 @@ export const verify_account = async function (req) {
1364
1414
  export const validate_user_plan = async function (req) {
1365
1415
  const { account_id, app_obj } = req;
1366
1416
 
1417
+ // Advertising campaigns are charged per-campaign (Stripe), NOT plan-capped — they
1418
+ // (and their team sharing) are available on EVERY plan, free included. Exempt them
1419
+ // from the plan gate so free accounts can invite collaborators to a campaign.
1420
+ if (app_obj?.app_type === 'advertising') return { code: 1, data: { membership_plan: 'advertising_exempt' } };
1421
+
1367
1422
  const apps_ret = await db_module.get_couch_view('xuda_master', 'user_apps_count', {
1368
1423
  startkey: [account_id, ''],
1369
1424
  endkey: [account_id, 'ZZZZZ'],
@@ -1391,8 +1446,13 @@ export const validate_user_plan = async function (req) {
1391
1446
  return { code: -7, data: 'error - no plan defined' };
1392
1447
  }
1393
1448
 
1394
- // validate number of projects
1395
- if (app_obj.app_type === 'master' && ret_obj.master >= plan.features.projects) {
1449
+ // validate number of projects.
1450
+ // The system account-project (is_account_project) backs login + the user
1451
+ // drive and is created automatically by login_maintenance_fix — it must
1452
+ // NEVER be blocked by the plan's project cap, or an account at the limit can
1453
+ // never be provisioned and gets permanently locked out (get_gtp_token_info
1454
+ // throws "fix: account_project_id" -> 401). Exempt it from the count.
1455
+ if (app_obj.app_type === 'master' && !app_obj.is_account_project && ret_obj.master >= plan.features.projects) {
1396
1456
  return {
1397
1457
  code: -8,
1398
1458
  data: `Number of projects (${ret.data.membership_plan}) exceeds to the ${plan.features.projects} plan limits`,
@@ -2260,52 +2320,34 @@ export const validate_account_topup = async function (uid, items = []) {
2260
2320
  if (code < 0) {
2261
2321
  throw new Error(data);
2262
2322
  }
2263
- let topup = 0;
2264
- for (const item of items) {
2265
- topup += get_prices(uid, item);
2266
- }
2323
+ // POSTPAID billing: paid features (VPS, custom domain, xuda subdomain, add-ons)
2324
+ // now bill on the Stripe invoice at cycle close — we NO LONGER require a prepaid
2325
+ // credit balance up front, only a working payment method. `items` is kept for
2326
+ // call-site compatibility but is no longer used to gate on a prepaid amount.
2267
2327
 
2328
+ // Gate 1: there must be a card on file to bill against.
2268
2329
  if (!data?.customer_obj?.default_source) {
2269
2330
  let err = new Error('no card on file');
2270
2331
  err.code = -90;
2271
2332
  err.billing_problem = true;
2272
2333
  throw err;
2273
- // throw new Error('no card on file');
2274
2334
  }
2275
2335
 
2336
+ // Gate 2: a prior invoice that failed to charge is a real billing problem —
2337
+ // block new paid usage until the card is fixed (otherwise unpaid usage runs
2338
+ // unbounded). This is "pay your overdue invoice", not a prepaid top-up.
2276
2339
  if (data?.balance?.past_due) {
2277
2340
  let err = new Error(`past due ${data.balance.past_due}`);
2278
2341
  err.code = -91;
2279
2342
  err.billing_problem = true;
2280
- err.topup = topup + data.balance.past_due;
2343
+ err.topup = data.balance.past_due;
2281
2344
  err.open_invoices = data?.open_invoices;
2282
2345
  throw err;
2283
2346
  }
2284
- // if (data?.balance?.past_due) {
2285
- // let err = new Error(`past_due ${data?.balance?.past_due}`);
2286
- // err.code = -91;
2287
- // err.billing_problem = true;
2288
- // err.topup = topup;
2289
- // throw err;
2290
- // }
2291
-
2292
- const balance = data?.balance?.account || 0; // minus balance represents positive balance
2293
-
2294
- if (balance > 0) {
2295
- let err = new Error(`negative balance ${-balance}`);
2296
- err.code = -92;
2297
- err.billing_problem = true;
2298
- err.topup = topup - balance; // ask for whole balance
2299
- throw err;
2300
- }
2301
2347
 
2302
- if (topup + balance > 0) {
2303
- let err = new Error(`not enough balance ${topup + balance}`);
2304
- err.code = -93;
2305
- err.billing_problem = true;
2306
- err.topup = topup;
2307
- throw err;
2308
- }
2348
+ // No prepaid-credit / "not enough balance" gate anymore — usage accrues on the
2349
+ // app_cost ledger and is charged on the next invoice (Stripe applies any credit
2350
+ // balance first, then the card).
2309
2351
 
2310
2352
  await release_account_billing_hold_if_current(uid);
2311
2353
 
@@ -2490,19 +2532,11 @@ export const onboarding_completed = async function (req, job_id, headers) {
2490
2532
  account_doc.isBoarded = true;
2491
2533
  const save_ret = await db_module.save_couch_doc('xuda_accounts', account_doc);
2492
2534
 
2493
- if (account_doc.account_info?.is_xuda_network_ambassador === true) {
2494
- console.log('[onboarding_completed] suppressing welcome_aboard for xuda.network ambassador', uid, account_doc.account_info.email);
2495
- } else {
2496
- notification_msa.submit_notification({
2497
- type: 'account',
2498
- app_id: null,
2499
- uid_arr: [uid],
2500
- topic: 'welcome_aboard',
2501
- params: { name: account_doc.account_info.first_name, email: account_doc.account_info.email, dashboard_url: 'https://xuda.ai/dashboard' },
2502
- ref: null,
2503
- email: null,
2504
- });
2505
- }
2535
+ // Welcome email is sent once per account by maybe_send_welcome_email, which
2536
+ // is also triggered when avatar generation completes (so it reaches every
2537
+ // signup surface, not only the dashboard onboarding form). It is idempotent
2538
+ // (welcome_email_sent_ts) and suppresses mentors/ambassadors.
2539
+ maybe_send_welcome_email(uid);
2506
2540
 
2507
2541
  return save_ret;
2508
2542
  } catch (err) {
@@ -2510,6 +2544,55 @@ export const onboarding_completed = async function (req, job_id, headers) {
2510
2544
  }
2511
2545
  };
2512
2546
 
2547
+ // Sends the welcome_aboard email exactly once per account. Safe to call from
2548
+ // multiple triggers (avatar-completion, onboarding_completed) and across every
2549
+ // signup surface (xuda.ai, Google OAuth, xuda.fashion, xuda.network, chat
2550
+ // widget, public profile). Skips mentors/ambassadors (is_xuda_network_ambassador).
2551
+ export const maybe_send_welcome_email = async function (uid) {
2552
+ try {
2553
+ const account_doc = await db_module.get_couch_doc_native('xuda_accounts', uid);
2554
+ if (!account_doc || !account_doc.account_info) return { code: -1, data: 'no account' };
2555
+ if (account_doc.account_info.is_xuda_network_ambassador === true) {
2556
+ console.log('[maybe_send_welcome_email] suppressing for xuda.network ambassador/mentor', uid);
2557
+ return { code: 0, data: 'ambassador' };
2558
+ }
2559
+ if (account_doc.welcome_email_sent_ts) return { code: 0, data: 'already sent' };
2560
+
2561
+ const host = _conf.is_debug ? process.env.XUDA_HOSTNAME || _conf.domain : _conf.domain;
2562
+ const username = account_doc.account_info.username || uid;
2563
+ const base = `https://${host}`;
2564
+ const public_url = `${base}/public_profiles/${encodeURIComponent(username)}`;
2565
+ const params = {
2566
+ name: account_doc.account_info.first_name || 'there',
2567
+ dashboard_url: `${base}/dashboard`,
2568
+ public_url,
2569
+ public_page_label: `${host}/public_profiles/${username}`,
2570
+ qr: `${public_url}/qr.png`,
2571
+ gif_base: `${base}/dist/images/email`,
2572
+ };
2573
+ await notification_msa.submit_notification({ type: 'account', app_id: null, uid_arr: [uid], topic: 'welcome_aboard', params, ref: null, email: null });
2574
+
2575
+ account_doc.welcome_email_sent_ts = Date.now();
2576
+ await db_module.save_couch_doc('xuda_accounts', account_doc);
2577
+ return { code: 1, data: 'sent' };
2578
+ } catch (err) {
2579
+ console.error('[maybe_send_welcome_email]', err.message);
2580
+ return { code: -1, data: err.message };
2581
+ }
2582
+ };
2583
+
2584
+ // Resolve an account uid from a public username (account_info.username).
2585
+ // Used by the public-profile route so /public_profiles/<username> resolves.
2586
+ export const get_uid_by_username = async function (username) {
2587
+ if (!username) return null;
2588
+ const ret = await db_module.find_couch_query('xuda_accounts', {
2589
+ selector: { 'account_info.username': username },
2590
+ fields: ['_id'],
2591
+ limit: 1,
2592
+ });
2593
+ return ret?.docs?.[0]?._id || null;
2594
+ };
2595
+
2513
2596
  export const ts_contact = async function (uid, contact_id) {
2514
2597
  try {
2515
2598
  const contact_doc = await get_contact(uid, contact_id);
@@ -2603,12 +2686,44 @@ const set_account_profile_picture = async function (uid, account_uid, metadata,
2603
2686
 
2604
2687
  const account_save_ret = await db_module.save_couch_doc('xuda_accounts', account_obj);
2605
2688
  await update_account_profile_picture_status(account_uid, 3);
2689
+ // Avatar finished generating -> the account is fully set up; send the
2690
+ // one-time welcome email (idempotent, skips mentors/ambassadors).
2691
+ maybe_send_welcome_email(account_uid);
2606
2692
  }
2607
2693
  } catch (err) {
2608
2694
  await update_account_profile_picture_status(account_uid, 1, err.message);
2609
2695
  }
2610
2696
  };
2611
2697
 
2698
+ // Internal trigger used by the widget Google-signup flow: when a freshly-created
2699
+ // visitor account already has a profile_picture (their Google photo) but no
2700
+ // generated avatar yet, kick off avatar generation. set_account_profile_picture
2701
+ // maintains profile_avatar_stat (1 → 2 → 3); the caller polls that. Mirrors the
2702
+ // opportunistic trigger in update_account_info (profile_avatar_stat !== 2 guards
2703
+ // against re-triggering while a generation is mid-flight).
2704
+ export const ensure_profile_avatar = async function (req, job_id, headers) {
2705
+ try {
2706
+ const { uid } = req || {};
2707
+ if (!uid) return { code: -1, data: 'missing uid' };
2708
+ const { code, data: account_obj } = await db_module.get_couch_doc('xuda_accounts', uid);
2709
+ if (code < 0 || !account_obj) return { code: -1, data: 'account not found' };
2710
+ const info = account_obj.account_info || {};
2711
+ if (info.profile_picture && !info.profile_avatar && info.profile_avatar_stat !== 2) {
2712
+ // Best-effort profile context for AI-usage attribution. A freshly-created
2713
+ // widget visitor may have no profile/project yet — tolerate that.
2714
+ let account_profile_info;
2715
+ try {
2716
+ account_profile_info = await get_active_account_profile_info(uid);
2717
+ } catch (e) {}
2718
+ // fire-and-forget inside this worker; generation is heavy (vision + image ops)
2719
+ set_account_profile_picture(uid, uid, info, job_id, headers, account_profile_info);
2720
+ }
2721
+ return { code: 1, data: { profile_avatar_stat: info.profile_avatar_stat || 0 } };
2722
+ } catch (err) {
2723
+ return { code: -1, data: err.message };
2724
+ }
2725
+ };
2726
+
2612
2727
  setTimeout(async () => {
2613
2728
  const app_id = 'prj712ffdf5aa8adce6cedef988f9c12392'; //'prj3937cb6f9a31c8c7dea25055bba845b1'; //
2614
2729
  const uid = 'd39126e0e2c51ffbd1aad10709fc8335';
@@ -4015,6 +4130,7 @@ export const update_entity_account_profiles = async function (req, job_id, heade
4015
4130
  };
4016
4131
 
4017
4132
  export const get_contact = async function (uid, contact_id) {
4133
+ if (!contact_id) return null;
4018
4134
  const account_profile_info = await get_active_account_profile_info(uid);
4019
4135
 
4020
4136
  const contact_ret = await db_module.get_app_couch_doc_native(account_profile_info.app_id, contact_id);
@@ -4291,6 +4407,34 @@ export const get_account_ai_usage_old = async function (req, job_id, headers) {
4291
4407
  }
4292
4408
  };
4293
4409
 
4410
+ // Push the account's live AI-credit balance to its dashboard WS room, so every
4411
+ // meter (the AiPrompt meter, the sidenav ring, the usage popup) updates the
4412
+ // instant credits are spent or topped up — no refresh. Debounced per-uid so a
4413
+ // burst of usage records (a streaming chat writing many chunks) collapses into a
4414
+ // single balance recompute + emit. Reuses get_account_ai_usage (the ledger read)
4415
+ // and emit_message_to_dashboard (the same uid-room push used for account updates).
4416
+ const _credits_broadcast_timers = {};
4417
+ export const broadcast_credits = function (uid) {
4418
+ if (!uid || uid === 'system' || uid === 'webhook') return;
4419
+ clearTimeout(_credits_broadcast_timers[uid]);
4420
+ _credits_broadcast_timers[uid] = setTimeout(async () => {
4421
+ delete _credits_broadcast_timers[uid];
4422
+ try {
4423
+ const ret = await get_account_ai_usage({ uid });
4424
+ if (!ret || ret.code !== 55) return;
4425
+ const max = Math.round((ret.data?.credits?.total || 0) * 100) / 100;
4426
+ const used = Math.round((ret.data?.usage?.total || 0) * 100) / 100;
4427
+ ws_dashboard_msa.emit_message_to_dashboard({
4428
+ service: 'credits_update',
4429
+ to: [uid],
4430
+ data: { used, max, remaining: Math.round((max - used) * 100) / 100, by_source: ret.data?.credits || {} },
4431
+ });
4432
+ } catch (e) {
4433
+ console.error('[broadcast_credits]', e?.message || e);
4434
+ }
4435
+ }, 800);
4436
+ };
4437
+
4294
4438
  export const record_ai_usage = async function (uid, input_tokens, output_tokens, source, prompt, model, metadata = {}, account_profile_info, tools) {
4295
4439
  try {
4296
4440
  if (!account_profile_info) throw new Error('missing account_profile_info');
@@ -4319,6 +4463,7 @@ export const record_ai_usage = async function (uid, input_tokens, output_tokens,
4319
4463
  };
4320
4464
  const save_ret = await db_module.save_couch_doc('xuda_usage', usage_doc);
4321
4465
  // console.log(save_ret);
4466
+ broadcast_credits(uid); // live meter: this account just spent credits
4322
4467
  } catch (err) {
4323
4468
  console.error(err);
4324
4469
  }
@@ -4354,6 +4499,7 @@ export const record_ai_credit = async function (uid, credits = 0, source, detail
4354
4499
  };
4355
4500
  const save_ret = await db_module.save_couch_doc('xuda_billing', credit_doc);
4356
4501
  // console.log(save_ret);
4502
+ broadcast_credits(credited_uid); // live meter: this account just gained credits
4357
4503
  return save_ret;
4358
4504
  } catch (err) {
4359
4505
  if (!err?.message?.includes('already credited!')) {
package/index_ms.mjs CHANGED
@@ -33,18 +33,8 @@ export const increment_account_usage = async function (...args) {
33
33
  return await broker.send_to_queue("increment_account_usage", ...args);
34
34
  };
35
35
 
36
- // accrue_deployment_costs removed — on-demand billing computes
37
- // from app_cost timestamps. See compute_cycle_billable_amount in
38
- // deploy_module/cost.mjs and the get_billing_metrics +
39
- // flush_deployment_usage_to_stripe entry points in stripe_module.
40
-
41
- export const backfill_app_costs = async function (...args) {
42
- return await broker.send_to_queue("backfill_app_costs", ...args);
43
- };
44
-
45
- export const mark_app_terminated = async function (...args) {
46
- return await broker.send_to_queue("mark_app_terminated", ...args);
47
- };
36
+ // mark_app_terminated removed — replaced by app_module.pre_destroy_app
37
+ // invoked via http_module's pre_dispatch hook on destroy_app.
48
38
 
49
39
  export const recompute_abuse_signals = async function (...args) {
50
40
  return await broker.send_to_queue("recompute_abuse_signals", ...args);
@@ -54,12 +44,16 @@ export const get_flagged_accounts = async function (...args) {
54
44
  return await broker.send_to_queue("get_flagged_accounts", ...args);
55
45
  };
56
46
 
47
+ export const sweep_abuse_signals = async function (...args) {
48
+ return await broker.send_to_queue("sweep_abuse_signals", ...args);
49
+ };
50
+
57
51
  export const mark_account_reviewed = async function (...args) {
58
52
  return await broker.send_to_queue("mark_account_reviewed", ...args);
59
53
  };
60
54
 
61
- export const sweep_abuse_signals = async function (...args) {
62
- return await broker.send_to_queue("sweep_abuse_signals", ...args);
55
+ export const backfill_app_costs = async function (...args) {
56
+ return await broker.send_to_queue("backfill_app_costs", ...args);
63
57
  };
64
58
 
65
59
  export const get_account_data = async function (...args) {
@@ -102,6 +96,10 @@ export const get_account_name = async function (...args) {
102
96
  return await broker.send_to_queue("get_account_name", ...args);
103
97
  };
104
98
 
99
+ export const get_uid_by_username = async function (...args) {
100
+ return await broker.send_to_queue("get_uid_by_username", ...args);
101
+ };
102
+
105
103
  export const account_validate_username = async function (...args) {
106
104
  return await broker.send_to_queue("account_validate_username", ...args);
107
105
  };
@@ -206,6 +204,10 @@ export const ts_contact = async function (...args) {
206
204
  return await broker.send_to_queue("ts_contact", ...args);
207
205
  };
208
206
 
207
+ export const ensure_profile_avatar = async function (...args) {
208
+ return await broker.send_to_queue("ensure_profile_avatar", ...args);
209
+ };
210
+
209
211
  export const add_contact = async function (...args) {
210
212
  return await broker.send_to_queue("add_contact", ...args);
211
213
  };
@@ -353,3 +355,15 @@ export const read_accounts_emails = async function (...args) {
353
355
  export const process_accounts_emails = async function (...args) {
354
356
  return await broker.send_to_queue("process_accounts_emails", ...args);
355
357
  };
358
+
359
+ export const get_account_vps = async function (...args) {
360
+ return await broker.send_to_queue("get_account_vps", ...args);
361
+ };
362
+
363
+ export const get_account_advertising = async function (...args) {
364
+ return await broker.send_to_queue("get_account_advertising", ...args);
365
+ };
366
+
367
+ export const get_account_static_websites = async function (...args) {
368
+ return await broker.send_to_queue("get_account_static_websites", ...args);
369
+ };
package/index_msa.mjs CHANGED
@@ -33,31 +33,27 @@ export const increment_account_usage = function (...args) {
33
33
  broker.send_to_queue_async("increment_account_usage", ...args);
34
34
  };
35
35
 
36
- // accrue_deployment_costs removed — on-demand billing. See
37
- // compute_cycle_billable_amount in deploy_module/cost.mjs.
36
+ // mark_app_terminated removed — replaced by app_module.pre_destroy_app
37
+ // invoked via http_module's pre_dispatch hook on destroy_app.
38
38
 
39
- export const backfill_app_costs = function (...args) {
40
- broker.send_to_queue_async("backfill_app_costs", ...args);
39
+ export const recompute_abuse_signals = function (...args) {
40
+ broker.send_to_queue_async("recompute_abuse_signals", ...args);
41
41
  };
42
42
 
43
- export const mark_app_terminated = function (...args) {
44
- broker.send_to_queue_async("mark_app_terminated", ...args);
43
+ export const get_flagged_accounts = function (...args) {
44
+ broker.send_to_queue_async("get_flagged_accounts", ...args);
45
45
  };
46
46
 
47
- export const recompute_abuse_signals = function (...args) {
48
- broker.send_to_queue_async("recompute_abuse_signals", ...args);
47
+ export const sweep_abuse_signals = function (...args) {
48
+ broker.send_to_queue_async("sweep_abuse_signals", ...args);
49
49
  };
50
50
 
51
- export const get_flagged_accounts = function (...args) {
52
- broker.send_to_queue_async("get_flagged_accounts", ...args);
51
+ export const mark_account_reviewed = function (...args) {
52
+ broker.send_to_queue_async("mark_account_reviewed", ...args);
53
53
  };
54
54
 
55
- export const mark_account_reviewed = function (...args) {
56
- broker.send_to_queue_async("mark_account_reviewed", ...args);
57
- };
58
-
59
- export const sweep_abuse_signals = function (...args) {
60
- broker.send_to_queue_async("sweep_abuse_signals", ...args);
55
+ export const backfill_app_costs = function (...args) {
56
+ broker.send_to_queue_async("backfill_app_costs", ...args);
61
57
  };
62
58
 
63
59
  export const get_account_data = function (...args) {
@@ -76,6 +72,14 @@ export const get_account_deployments = function (...args) {
76
72
  broker.send_to_queue_async("get_account_deployments", ...args);
77
73
  };
78
74
 
75
+ export const get_account_advertising = function (...args) {
76
+ broker.send_to_queue_async("get_account_advertising", ...args);
77
+ };
78
+
79
+ export const get_account_static_websites = function (...args) {
80
+ broker.send_to_queue_async("get_account_static_websites", ...args);
81
+ };
82
+
79
83
  export const get_account_instances = function (...args) {
80
84
  broker.send_to_queue_async("get_account_instances", ...args);
81
85
  };
@@ -204,6 +208,10 @@ export const ts_contact = function (...args) {
204
208
  broker.send_to_queue_async("ts_contact", ...args);
205
209
  };
206
210
 
211
+ export const ensure_profile_avatar = function (...args) {
212
+ broker.send_to_queue_async("ensure_profile_avatar", ...args);
213
+ };
214
+
207
215
  export const add_contact = function (...args) {
208
216
  broker.send_to_queue_async("add_contact", ...args);
209
217
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xuda.io/account_module",
3
- "version": "1.2.2257",
3
+ "version": "1.2.2259",
4
4
  "description": "Xuda Account Server Module",
5
5
  "main": "index.mjs",
6
6
  "dependencies": {