191 lines
6.9 KiB
TypeScript
191 lines
6.9 KiB
TypeScript
import { PUBLIC_BETA_GATE_READY_SQL } from "./launch-gates.ts";
|
|
|
|
export type BetaAccessRequestStatus =
|
|
| "requested"
|
|
| "approved"
|
|
| "declined"
|
|
| "cancelled";
|
|
|
|
/**
|
|
* Reserve one account-level pending request by first reserving its replay key.
|
|
* Parameters: scope, key, hash, response JSON, expiry, now, account id.
|
|
*/
|
|
export const CREATE_ACCESS_REQUEST_IDEMPOTENCY_SQL = `
|
|
INSERT INTO idempotency_records
|
|
(scope, key, request_hash, response_json, status_code, expires_at, created_at)
|
|
SELECT ?1, ?2, ?3, ?4, 201, ?5, ?6
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM beta_access_requests
|
|
WHERE account_id = ?7 AND status = 'requested'
|
|
)
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM entitlement_grants
|
|
WHERE account_id = ?7 AND state = 'active' AND starts_at <= ?6
|
|
AND (ends_at IS NULL OR ends_at > ?6) AND revoked_at IS NULL
|
|
)
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM beta_programs
|
|
WHERE state = 'active' AND starts_at <= ?6
|
|
AND (ends_at IS NULL OR ends_at > ?6)
|
|
AND ${PUBLIC_BETA_GATE_READY_SQL}
|
|
)
|
|
`;
|
|
|
|
/** Parameters: id, account, OS, slots, use case, now, scope, key, hash. */
|
|
export const CREATE_ACCESS_REQUEST_SQL = `
|
|
INSERT INTO beta_access_requests
|
|
(id, account_id, status, preferred_os, requested_slots, use_case,
|
|
requested_at, created_at, updated_at)
|
|
SELECT ?1, ?2, 'requested', ?3, ?4, ?5, ?6, ?6, ?6
|
|
WHERE EXISTS (
|
|
SELECT 1 FROM idempotency_records
|
|
WHERE scope = ?7 AND key = ?8 AND request_hash = ?9
|
|
)
|
|
`;
|
|
|
|
/**
|
|
* Reserve cancellation only while the same account still owns a pending row.
|
|
* Parameters: scope, key, hash, response JSON, expiry, now, request id, account.
|
|
*/
|
|
export const CREATE_ACCESS_CANCELLATION_IDEMPOTENCY_SQL = `
|
|
INSERT INTO idempotency_records
|
|
(scope, key, request_hash, response_json, status_code, expires_at, created_at)
|
|
SELECT ?1, ?2, ?3, ?4, 200, ?5, ?6
|
|
FROM beta_access_requests
|
|
WHERE id = ?7 AND account_id = ?8 AND status = 'requested'
|
|
`;
|
|
|
|
/** Parameters: now, request id, account, scope, key, hash. */
|
|
export const CANCEL_ACCESS_REQUEST_SQL = `
|
|
UPDATE beta_access_requests
|
|
SET status = 'cancelled', cancelled_at = ?1, updated_at = ?1
|
|
WHERE id = ?2 AND account_id = ?3 AND status = 'requested'
|
|
AND EXISTS (
|
|
SELECT 1 FROM idempotency_records
|
|
WHERE scope = ?4 AND key = ?5 AND request_hash = ?6
|
|
)
|
|
`;
|
|
|
|
/**
|
|
* Reserve an administrator decision only while the request is pending.
|
|
* Parameters: scope, key, hash, response JSON, status code, expiry, now, request.
|
|
*/
|
|
export const CREATE_ACCESS_RESOLUTION_IDEMPOTENCY_SQL = `
|
|
INSERT INTO idempotency_records
|
|
(scope, key, request_hash, response_json, status_code, expires_at, created_at)
|
|
SELECT ?1, ?2, ?3, ?4, ?5, ?6, ?7
|
|
FROM beta_access_requests
|
|
WHERE id = ?8 AND status = 'requested'
|
|
`;
|
|
|
|
/**
|
|
* Create the non-monetary invitation for an approved request.
|
|
* Parameters: grant id, request id/source ref, capacity, now, end, reason,
|
|
* actor, request id, scope, key, hash.
|
|
*/
|
|
export const CREATE_APPROVED_INVITATION_SQL = `
|
|
INSERT INTO entitlement_grants
|
|
(id, account_id, host_id, source, source_ref, capacity_slots,
|
|
starts_at, ends_at, state, reason, created_by, created_at)
|
|
SELECT ?1, account_id, NULL, 'admin_exemption', ?2, ?3,
|
|
?4, ?5, 'active', ?6, ?7, ?4
|
|
FROM beta_access_requests
|
|
WHERE id = ?8 AND status = 'requested'
|
|
AND EXISTS (
|
|
SELECT 1 FROM idempotency_records
|
|
WHERE scope = ?9 AND key = ?10 AND request_hash = ?11
|
|
)
|
|
`;
|
|
|
|
/** Parameters: response, actor, grant id, now, request id, scope, key, hash. */
|
|
export const APPROVE_ACCESS_REQUEST_SQL = `
|
|
UPDATE beta_access_requests
|
|
SET status = 'approved', admin_response = ?1, resolved_by = ?2,
|
|
invitation_grant_id = ?3, resolved_at = ?4, updated_at = ?4
|
|
WHERE id = ?5 AND status = 'requested'
|
|
AND EXISTS (SELECT 1 FROM entitlement_grants WHERE id = ?3)
|
|
AND EXISTS (
|
|
SELECT 1 FROM idempotency_records
|
|
WHERE scope = ?6 AND key = ?7 AND request_hash = ?8
|
|
)
|
|
`;
|
|
|
|
/** Parameters: response, actor, now, request id, scope, key, hash. */
|
|
export const DECLINE_ACCESS_REQUEST_SQL = `
|
|
UPDATE beta_access_requests
|
|
SET status = 'declined', admin_response = ?1, resolved_by = ?2,
|
|
resolved_at = ?3, updated_at = ?3
|
|
WHERE id = ?4 AND status = 'requested'
|
|
AND EXISTS (
|
|
SELECT 1 FROM idempotency_records
|
|
WHERE scope = ?5 AND key = ?6 AND request_hash = ?7
|
|
)
|
|
`;
|
|
|
|
/**
|
|
* Manual invitations are only for proactive invitations. When an account has
|
|
* a pending request, administrators must resolve that request so user-visible
|
|
* state and the grant cannot diverge.
|
|
* Parameters: scope, key, hash, response JSON, expiry, now, account id.
|
|
*/
|
|
export const CREATE_MANUAL_INVITATION_IDEMPOTENCY_SQL = `
|
|
INSERT INTO idempotency_records
|
|
(scope, key, request_hash, response_json, status_code, expires_at, created_at)
|
|
SELECT ?1, ?2, ?3, ?4, 201, ?5, ?6
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM beta_access_requests
|
|
WHERE account_id = ?7 AND status = 'requested'
|
|
)
|
|
`;
|
|
|
|
/** Parameters: grant fields followed by scope, key and hash. */
|
|
export const CREATE_MANUAL_INVITATION_SQL = `
|
|
INSERT INTO entitlement_grants
|
|
(id, account_id, host_id, source, source_ref, capacity_slots,
|
|
starts_at, ends_at, state, reason, created_by, created_at)
|
|
SELECT ?1, ?2, NULL, 'admin_exemption', ?3, ?4,
|
|
?5, ?6, 'active', ?7, ?8, ?9
|
|
WHERE EXISTS (
|
|
SELECT 1 FROM idempotency_records
|
|
WHERE scope = ?10 AND key = ?11 AND request_hash = ?12
|
|
)
|
|
`;
|
|
|
|
export const PUBLIC_BETA_ACCESS_RESPONSE =
|
|
"公开免费测试已经开放,当前不再需要单独闭测邀请。";
|
|
|
|
/**
|
|
* Close stale pending requests only when an active public beta and every P0
|
|
* evidence gate are simultaneously true inside the same D1 batch.
|
|
* Parameters: user-facing response, actor, now.
|
|
*/
|
|
export const FULFILL_ACCESS_REQUESTS_BY_PUBLIC_BETA_SQL = `
|
|
UPDATE beta_access_requests
|
|
SET status = 'approved', admin_response = ?1, resolved_by = ?2,
|
|
invitation_grant_id = NULL, resolved_at = ?3, updated_at = ?3
|
|
WHERE status = 'requested'
|
|
AND EXISTS (
|
|
SELECT 1 FROM beta_programs
|
|
WHERE state = 'active' AND starts_at <= ?3
|
|
AND (ends_at IS NULL OR ends_at > ?3)
|
|
AND ${PUBLIC_BETA_GATE_READY_SQL}
|
|
)
|
|
`;
|
|
|
|
/** Parameters: actor, response, correlation id, now. */
|
|
export const AUDIT_PUBLIC_BETA_ACCESS_FULFILLMENT_SQL = `
|
|
INSERT OR IGNORE INTO audit_events
|
|
(id, actor_id, action, target_type, target_id, reason,
|
|
before_json, after_json, correlation_id, created_at)
|
|
SELECT 'audit_public_beta_' || substr(id, 8), ?1,
|
|
'beta_access.fulfilled_by_public_beta', 'beta_access_request', id,
|
|
'公开免费测试开放,待审申请无需单独邀请',
|
|
'{"status":"requested"}',
|
|
json_object('status', 'approved', 'adminResponse', ?2,
|
|
'invitationGrantId', NULL),
|
|
?3, ?4
|
|
FROM beta_access_requests
|
|
WHERE status = 'approved' AND resolved_by = ?1 AND resolved_at = ?4
|
|
AND invitation_grant_id IS NULL AND admin_response = ?2
|
|
`;
|