@secondlayer/shared 11.4.1 → 11.4.3

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.
@@ -264,6 +264,21 @@ interface MagicLinksTable {
264
264
  failed_attempts: Generated<number>;
265
265
  created_at: Generated<Date>;
266
266
  }
267
+ /** One-shot hashed tokens that attach a play ghost to an email at claim. */
268
+ interface ClaimTokensTable {
269
+ id: Generated<string>;
270
+ account_id: string;
271
+ token_hash: string;
272
+ created_at: Generated<Date>;
273
+ expires_at: Date;
274
+ used_at: Date | null;
275
+ }
276
+ /** 3 play provisions per IP per UTC day. PK (ip_hash, day); `count` caps at 3. */
277
+ interface PlayProvisionsTable {
278
+ ip_hash: string;
279
+ day: string;
280
+ count: Generated<number>;
281
+ }
267
282
  interface SubgraphProcessingStatsTable {
268
283
  id: Generated<string>;
269
284
  subgraph_name: string;
@@ -762,6 +777,8 @@ interface Database {
762
777
  accounts: AccountsTable;
763
778
  sessions: SessionsTable;
764
779
  magic_links: MagicLinksTable;
780
+ claim_tokens: ClaimTokensTable;
781
+ play_provisions: PlayProvisionsTable;
765
782
  subgraph_health_snapshots: SubgraphHealthSnapshotsTable;
766
783
  subgraph_processing_stats: SubgraphProcessingStatsTable;
767
784
  subgraph_table_snapshots: SubgraphTableSnapshotsTable;
@@ -771,6 +788,7 @@ interface Database {
771
788
  processed_stripe_events: ProcessedStripeEventsTable;
772
789
  account_spend_caps: AccountSpendCapsTable;
773
790
  account_credits: AccountCreditsTable;
791
+ hosted_meter_days: HostedMeterDaysTable;
774
792
  subscriptions: SubscriptionsTable;
775
793
  subscription_outbox: SubscriptionOutboxTable;
776
794
  subscription_deliveries: SubscriptionDeliveriesTable;
@@ -870,6 +888,15 @@ interface AccountCreditsTable {
870
888
  refill_last_at: Date | null;
871
889
  updated_at: Generated<Date>;
872
890
  }
891
+ /** Daily idempotency ledger for hosted subgraph running + storage meters. */
892
+ interface HostedMeterDaysTable {
893
+ day: string;
894
+ account_id: string;
895
+ subgraph_name: string;
896
+ kind: string;
897
+ usd_micros: string | number | bigint;
898
+ billed_at: Generated<Date>;
899
+ }
873
900
  /**
874
901
  * Archive fetch charge log (design-f089 gate). Append-only: one row per
875
902
  * priced attempt to fetch a partition object. `usd_micros` is 0 for
@@ -0,0 +1,31 @@
1
+ import { type Kysely, sql } from "kysely";
2
+ import { onControlPlane } from "../src/db/migration-role.ts";
3
+
4
+ /**
5
+ * Daily idempotency ledger for hosted subgraph running + storage meters.
6
+ * Control plane only. One row per (day, account, subgraph, kind) so the
7
+ * worker can INSERT ON CONFLICT DO NOTHING and debit only on first insert.
8
+ */
9
+ export async function up(db: Kysely<unknown>): Promise<void> {
10
+ await sql`SET lock_timeout = '30s'`.execute(db);
11
+ await onControlPlane(async () => {
12
+ await sql`
13
+ CREATE TABLE IF NOT EXISTS hosted_meter_days (
14
+ day date NOT NULL,
15
+ account_id text NOT NULL,
16
+ subgraph_name text NOT NULL,
17
+ kind text NOT NULL,
18
+ usd_micros bigint NOT NULL,
19
+ billed_at timestamptz NOT NULL DEFAULT now(),
20
+ PRIMARY KEY (day, account_id, subgraph_name, kind),
21
+ CHECK (kind IN ('running', 'storage'))
22
+ )
23
+ `.execute(db);
24
+ });
25
+ }
26
+
27
+ export async function down(db: Kysely<unknown>): Promise<void> {
28
+ await onControlPlane(async () => {
29
+ await sql`DROP TABLE IF EXISTS hosted_meter_days`.execute(db);
30
+ });
31
+ }
@@ -0,0 +1,42 @@
1
+ import { type Kysely, sql } from "kysely";
2
+ import { onControlPlane } from "../src/db/migration-role.ts";
3
+
4
+ /**
5
+ * Recreate claim_tokens (dropped in 0118) for accountless play, plus
6
+ * play_provisions for the 3-per-IP-per-UTC-day cap. Control plane only.
7
+ * Copy of 0093's claim_tokens shape: hashed one-shot tokens that attach a
8
+ * ghost account to an email at claim time.
9
+ */
10
+ export async function up(db: Kysely<unknown>): Promise<void> {
11
+ await sql`SET lock_timeout = '30s'`.execute(db);
12
+ await onControlPlane(async () => {
13
+ await sql`
14
+ CREATE TABLE claim_tokens (
15
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
16
+ account_id UUID NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
17
+ token_hash TEXT NOT NULL UNIQUE,
18
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
19
+ expires_at TIMESTAMPTZ NOT NULL,
20
+ used_at TIMESTAMPTZ
21
+ )
22
+ `.execute(db);
23
+ await sql`CREATE INDEX claim_tokens_account_id_idx ON claim_tokens (account_id)`.execute(
24
+ db,
25
+ );
26
+ await sql`
27
+ CREATE TABLE play_provisions (
28
+ ip_hash TEXT NOT NULL,
29
+ day DATE NOT NULL,
30
+ count INTEGER NOT NULL DEFAULT 1,
31
+ PRIMARY KEY (ip_hash, day)
32
+ )
33
+ `.execute(db);
34
+ });
35
+ }
36
+
37
+ export async function down(db: Kysely<unknown>): Promise<void> {
38
+ await onControlPlane(async () => {
39
+ await sql`DROP TABLE IF EXISTS play_provisions`.execute(db);
40
+ await sql`DROP TABLE IF EXISTS claim_tokens`.execute(db);
41
+ });
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/shared",
3
- "version": "11.4.1",
3
+ "version": "11.4.3",
4
4
  "description": "Internal building blocks shared across Secondlayer packages.",
5
5
  "license": "MIT",
6
6
  "repository": {