chore: initialize from frontend template 4dc033c

This commit is contained in:
DongHyeonka
2026-08-13 18:23:26 +09:00
commit 40107eec84
897 changed files with 234824 additions and 0 deletions
+200
View File
@@ -0,0 +1,200 @@
export const WEB_PUSH_LIMITS = Object.freeze({
decodedHintBytes: 3 * 1024,
hintFutureSkewMs: 5 * 60 * 1_000,
hintMaxLifetimeMs: 24 * 60 * 60 * 1_000,
handlerDeadlineMs: 10_000,
fenceOperationDeadlineMs: 2_000,
nativeOperationDeadlineMs: 30_000,
backendOperationDeadlineMs: 15_000,
notificationCleanupCount: 64,
notificationCleanupDeadlineMs: 2_000,
clientHandoffCount: 32,
} as const);
export const WEB_PUSH_PROTOCOLS = Object.freeze({
control: "PUSH_CONTROL_V1",
hint: "WEB_PUSH_HINT_V1",
click: "NOTIFICATION_CLICK_DATA_V1",
registration: "WEB_PUSH_REGISTRATION_V1",
reconciliation: "WEB_PUSH_RECONCILIATION_V1",
revoke: "WEB_PUSH_REVOKE_V1",
clickHandoff: "WEB_PUSH_CLICK_HANDOFF_V1",
reconcileRequired: "WEB_PUSH_RECONCILE_REQUIRED_V1",
} as const);
/**
* Product IDs stay opaque to the mechanism. The selected composition must
* provide a closed registry that resolves these syntactically validated IDs.
*/
export type NotificationTypeId = string;
export type NotificationRouteIntentId = string;
export type PushAuthoritySnapshot = Readonly<{
fenceGeneration: string;
sessionBindingEpoch: string;
releaseEpoch: string;
}>;
export type PushControlAssociationV1 =
| Readonly<{ state: "UNASSOCIATED" }>
| Readonly<{
state: "ACTIVE" | "REVOKED";
associationEpoch: string;
}>;
/**
* One origin-scoped durable authority record shared by the window and worker.
* It intentionally contains no account identifier or native subscription
* material. `updatedAt` is diagnostic metadata, never an ordering authority.
*/
export type PushControlV1 = Readonly<{
protocol: typeof WEB_PUSH_PROTOCOLS.control;
fenceGeneration: string;
sessionBindingEpoch: string;
releaseEpoch: string;
updatedAt: string;
association: PushControlAssociationV1;
}>;
export type WebPushHintV1 = Readonly<{
protocol: typeof WEB_PUSH_PROTOCOLS.hint;
notificationType: NotificationTypeId;
notificationId: string;
associationEpoch: string;
releaseEpoch: string;
issuedAt: string;
expiresAt: string;
routeIntent: NotificationRouteIntentId;
}>;
export type NotificationClickDataV1 = Readonly<{
protocol: typeof WEB_PUSH_PROTOCOLS.click;
notificationId: string;
routeIntent: NotificationRouteIntentId;
associationEpoch: string;
releaseEpoch: string;
expiresAt: string;
}>;
export type WebPushReadinessState =
| "PUSH_READY"
| "PUSH_PERMISSION_REQUIRED"
| "PUSH_DENIED"
| "PUSH_UNSUPPORTED"
| "PUSH_UNAVAILABLE";
export type WebPushUnavailableReason =
| "ABORTED"
| "BACKEND_ASSOCIATION_MISSING"
| "BACKEND_REVOKE_AMBIGUOUS"
| "BUSY"
| "CLOSED"
| "LOCAL_FENCE_UNSAFE"
| "NATIVE_UNSUBSCRIBE_AMBIGUOUS"
| "NATIVE_SUBSCRIPTION_MISSING"
| "PERMISSION_DISMISSED"
| "REGISTRATION_NOT_ACTIVE"
| "REVOKED"
| "SESSION_AUTHORITY_CHANGED"
| "SUBSCRIPTION_KEY_MISMATCH"
| "WORKER_UNAVAILABLE";
export type WebPushReadiness = Readonly<{
state: WebPushReadinessState;
reason?: WebPushUnavailableReason;
}>;
export type WebPushOperation =
| "CONTROL_OPEN"
| "CONTROL_READ"
| "CONTROL_PREPARE"
| "CONTROL_ACTIVATE"
| "CONTROL_REVOKE"
| "CONTROL_PURGE"
| "PERMISSION_REQUEST"
| "SUBSCRIPTION_INSPECT"
| "SUBSCRIPTION_CREATE"
| "SUBSCRIPTION_RECONCILE"
| "SUBSCRIPTION_REVOKE"
| "PUSH_DECODE"
| "PUSH_HANDLE"
| "NOTIFICATION_SHOW"
| "NOTIFICATION_CLICK"
| "NOTIFICATION_CLEANUP";
export type WebPushFailureCode =
| "ABORTED"
| "ASSOCIATION_MISMATCH"
| "BLOCKED"
| "CONTRACT_REJECTED"
| "CONTROL_CORRUPT"
| "DEADLINE_EXCEEDED"
| "DECLARATIVE_PUSH_FORBIDDEN"
| "EXPIRED"
| "INVALID_INPUT"
| "LIMIT_EXCEEDED"
| "NATIVE_FAILURE"
| "PERMISSION_DENIED"
| "PROVIDER_UNAVAILABLE"
| "RELEASE_MISMATCH"
| "STALE_AUTHORITY"
| "STALE_REVISION"
| "TOMBSTONE_CONFLICT"
| "UNSUPPORTED";
export type WebPushFailure = Readonly<{
code: WebPushFailureCode;
operation: WebPushOperation;
retryable: boolean;
}>;
export type WebPushResult<Value> =
| Readonly<{ ok: true; value: Value }>
| Readonly<{ ok: false; error: WebPushFailure }>;
export type WebPushObservationEvent =
| "web_push_permission_finished"
| "web_push_registration_finished"
| "web_push_subscription_rotated"
| "web_push_hint_processed"
| "web_push_notification_finished"
| "web_push_click_dispatched"
| "web_push_association_revoked";
export type WebPushObservation = Readonly<{
event: WebPushObservationEvent;
outcome: "SUCCEEDED" | "FAILED" | "DEGRADED";
reason?: WebPushFailureCode | WebPushUnavailableReason;
}>;
export interface WebPushObserver {
record(observation: WebPushObservation): void;
}
export function webPushSuccess<Value>(
value: Value,
): WebPushResult<Value> {
return Object.freeze({ ok: true, value });
}
export function webPushFailure(
code: WebPushFailureCode,
operation: WebPushOperation,
retryable = false,
): WebPushResult<never> {
return Object.freeze({
ok: false,
error: Object.freeze({ code, operation, retryable }),
});
}
export function samePushAuthority(
left: PushAuthoritySnapshot,
right: PushAuthoritySnapshot,
): boolean {
return (
left.fenceGeneration === right.fenceGeneration &&
left.sessionBindingEpoch === right.sessionBindingEpoch &&
left.releaseEpoch === right.releaseEpoch
);
}