@vimine/sdk 0.3.5 → 0.3.6

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/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Registro delle modifiche
2
+
3
+ <!-- Fatto da scripts/news.mjs con le voci di news/entries.mjs (npm run news:write): si cambiano le voci, non questo file. -->
4
+
5
+ Le modifiche di `@vimine/sdk`, dalla più recente. Le stesse voci, accanto a quelle dell’API, in ogni lingua del
6
+ portale: https://developers.vimine.network/news/ (in English: https://developers.vimine.network/en/news/).
7
+
8
+ ## 0.3.6 — 29 ottobre 2026
9
+
10
+ - **La sessione dice l’associazione** — `getSession().aps` dice in quale associazione il socio ha fatto l’accesso (`slug`, `name`, `picture_url`) e resta quando il token si rinnova. Nei tipi generati arrivano `Spec.Regolamento`, `Spec.operations.getApsRegolamento` e `aps.website` in `Spec.ApsPublicConfig`.
11
+
12
+ ## 0.3.5 — 25 ottobre 2026
13
+
14
+ - **Cinese tradizionale nell’uso di Taiwan** — Gli elementi in cinese tradizionale seguono l’uso di Taiwan (登出, QR Code, 發生錯誤…): i testi erano stati convertiti automaticamente da quelli in cinese semplificato, parole comprese.
15
+
16
+ Le versioni precedenti sono nella storia del repository.
@@ -61,6 +61,8 @@ export interface ApsPublicConfig {
61
61
  picture_url?: string | null;
62
62
  citta?: string | null;
63
63
  provincia?: string | null;
64
+ /** The association's own website (http or https), or null when it gave none */
65
+ website?: string | null;
64
66
  enroll_enabled?: boolean;
65
67
  /** Whether a membership request would be taken now: enrolment on, a member more fits the plan, the association ready to collect requests, and its public door open. */
66
68
  accepting_requests?: boolean;
@@ -450,6 +452,22 @@ export interface PrivacyNoticeRef {
450
452
  effective_from?: string | null;
451
453
  }
452
454
  export type PrivacyNotice = unknown;
455
+ export interface Regolamento {
456
+ aps?: {
457
+ slug?: string;
458
+ name?: string;
459
+ };
460
+ uid: string;
461
+ version: number;
462
+ locale: string;
463
+ /** The association's own title for it */
464
+ title: string;
465
+ effective_from?: string | null;
466
+ sha256?: string | null;
467
+ rendered_sha256?: string;
468
+ content_md: string;
469
+ content_html: string;
470
+ }
453
471
  export interface LegalRef {
454
472
  /** The in-force version label shown (GET /v1/legal/{kind}) */
455
473
  version: string;
@@ -607,6 +625,7 @@ export declare const operations: {
607
625
  readonly getSubProcessors: readonly ["GET", "/v1/legal/sub-processors"];
608
626
  readonly getLegalDocument: readonly ["GET", "/v1/legal/{kind}"];
609
627
  readonly getApsPrivacyNotice: readonly ["GET", "/v1/aps/{slug}/privacy-notice"];
628
+ readonly getApsRegolamento: readonly ["GET", "/v1/aps/{slug}/regolamento"];
610
629
  readonly getApsStatuto: readonly ["GET", "/v1/aps/{slug}/statuto"];
611
630
  };
612
631
  export type OperationId = keyof typeof operations;
package/dist/generated.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // GENERATED by scripts/gen-types.mjs from openapi/v1.json — do not edit. Regenerate: npm run spec:types
2
- // Spec version 2026-10-18 · 47 paths · 36 schemas
2
+ // Spec version 2026-10-29 · 48 paths · 37 schemas
3
3
  /** Every operation of the document: id → [method, path]. */
4
4
  export const operations = {
5
5
  getOpenApi: ['GET', '/v1/openapi.json'],
@@ -54,6 +54,7 @@ export const operations = {
54
54
  getSubProcessors: ['GET', '/v1/legal/sub-processors'],
55
55
  getLegalDocument: ['GET', '/v1/legal/{kind}'],
56
56
  getApsPrivacyNotice: ['GET', '/v1/aps/{slug}/privacy-notice'],
57
+ getApsRegolamento: ['GET', '/v1/aps/{slug}/regolamento'],
57
58
  getApsStatuto: ['GET', '/v1/aps/{slug}/statuto'],
58
59
  };
59
60
  //# sourceMappingURL=generated.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generated.js","sourceRoot":"","sources":["../src/generated.ts"],"names":[],"mappings":"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","sourcesContent":["// GENERATED by scripts/gen-types.mjs from openapi/v1.json — do not edit. Regenerate: npm run spec:types\n// Spec version 2026-10-18 · 47 paths · 36 schemas\n\nexport interface Problem {\n type: string;\n title: string;\n status: number;\n detail?: string;\n code: string;\n request_id?: string;\n errors?: Array<{\n field?: string;\n code?: string;\n message?: string;\n }>;\n}\n\nexport interface Verification {\n status: \"active\" | \"inactive\";\n valid_until?: string;\n /** With `reason: not_yet_valid`: the card is genuine and active, and becomes usable at this moment */\n valid_from?: string;\n reason?: \"expired\" | \"invalid\" | \"not_yet_valid\";\n /** Present for registration tokens */\n kind?: \"card\" | \"registration\";\n event?: {\n slug?: string;\n starts_at?: string;\n } | null;\n}\n\nexport interface MembershipType {\n uid?: string;\n cod?: string;\n name?: string;\n description?: string | null;\n quota_amount?: number | null;\n currency?: string;\n expiry_model?: \"solar_year\" | \"rolling_12\" | \"rolling_24\" | \"prorated_solar\" | \"custom\";\n network_eligible?: boolean;\n}\n\nexport interface Statuto {\n aps?: {\n slug?: string;\n name?: string;\n };\n title: string;\n version: number;\n approved_on?: string | null;\n /** Of the uploaded document, when there is one */\n sha256?: string | null;\n /** The text as registered; empty when only a document was uploaded */\n content_md?: string;\n content_html: string;\n /** The uploaded document, a link valid for 15 minutes */\n document_url?: string | null;\n}\n\nexport interface ApsPublicConfig {\n /** The language this answer is written in */\n locale?: string;\n /** The languages the association offers: its own, plus those it enabled */\n locales?: Array<string>;\n aps: {\n slug?: string;\n name?: string;\n picture_url?: string | null;\n citta?: string | null;\n provincia?: string | null;\n enroll_enabled?: boolean;\n /** Whether a membership request would be taken now: enrolment on, a member more fits the plan, the association ready to collect requests, and its public door open. */\n accepting_requests?: boolean;\n /** True while Vimine registers people by invitation only (the private beta) and this association takes only the people it invited: `accepting_requests` is then false, and `POST /v1/enroll` answers 403 `not_available`. */\n invitation_only?: boolean;\n /** True for a sandbox: the test copy of an association that test clients work on, with synthetic members only. It never sends e-mail, takes no payments and is never in the Network. */\n sandbox?: boolean;\n /** How the association admits its members, so that an applicant can be told up front what to expect. `model`: `board` — the request waits for a decision of the association’s board, and any fee is paid after it; `provisional` — admitted at once, ratified by the board later; `automatic` — active as soon as the conditions are met. `delay_hours`: the hours between admission and a USABLE card (0 = at once): the membership is active from admission, the card counts at the door only afterwards (see `valid_from`). */\n admission?: {\n model?: \"board\" | \"provisional\" | \"automatic\";\n delay_hours?: number;\n };\n /** Kept for compatibility: true when `admission.model` is `board`. Read `admission` instead. */\n approval_required?: boolean;\n /** Whether the association collects its members’ address — of every member or of nobody. `none`: do not ask (an `address` sent anyway is not stored); `optional`; `required`: enrolment answers 422 without one. */\n member_address?: \"none\" | \"optional\" | \"required\";\n /** How to pay the fee, as the association words it */\n payment_instructions?: string | null;\n /** The activities of general interest the association carries out (Italian Third Sector Code, art. 5): `cod` is the letter of the article, `description` its Italian wording; one is marked as prevalent. */\n activity_sectors?: Array<{\n cod?: string;\n description?: string;\n prevalent?: boolean;\n }>;\n /** Present when the association is registered in the RUNTS (the Italian national register of Third Sector entities), as checked by the platform against the official public lists; null otherwise. Never typed by the association. */\n registry?: {\n /** Section of the register */\n section?: \"APS\" | \"ODV\" | \"EF\" | \"IS\" | \"RA\" | \"SOMS\" | \"ALTRI\" | null | null;\n /** Repertory number */\n number?: string | null;\n registered_on?: string | null;\n /** Date of the official list the check ran against */\n checked_on?: string | null;\n } | null;\n };\n membership_types: Array<MembershipType>;\n statuto: Statuto | unknown;\n /** The association's in-force privacy notice to members (full text: GET /v1/aps/{slug}/privacy-notice) */\n privacy_notice?: PrivacyNoticeRef | unknown;\n}\n\nexport interface FiscalCodeCheck {\n /** Codice fiscale (16 characters) */\n code: string;\n first_name?: string;\n last_name?: string;\n gender?: \"M\" | \"F\";\n /** Date of birth */\n date?: string;\n /** Birthplace: the comune, for a person born in Italy */\n place?: string;\n /** Birth country, ISO 3166-1 alpha-2. A code encodes the comune for people born in Italy and only the STATE for everybody else: anything but IT is compared with that state and `place` is ignored */\n country?: string;\n}\n\nexport interface FiscalCodeResult {\n valid?: boolean;\n error?: \"invalid\" | \"mismatch\" | null;\n /** What disagrees with the code, when `error` is `mismatch` */\n mismatches?: Array<\"lastName\" | \"firstName\" | \"gender\" | \"date\" | \"place\">;\n /** `names_swapped`: the code matches once surname and given name are exchanged */\n hints?: Array<\"names_swapped\">;\n /** The date of birth the code itself encodes */\n birth_date?: string | null;\n /** The birth country the code itself encodes, ISO 3166-1 alpha-2 (IT for a comune) */\n birth_country?: string | null;\n}\n\nexport interface CardKeys {\n keys?: Array<{\n kty?: string;\n crv?: string;\n x?: string;\n kid?: string;\n use?: string;\n alg?: string;\n }>;\n}\n\nexport interface SignupRequest {\n email: string;\n first_name: string;\n last_name: string;\n phone?: string | null;\n dob?: string | null;\n /** Demographic only: it is not cross-checked */\n gender?: \"M\" | \"F\" | null;\n /** Comune (born in Italy) or city, free text (born abroad) */\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string | null;\n /** Validated and cross-checked against the other fields when present */\n codicefiscale?: string | null;\n /** The person confirms a code that disagrees with their particulars (422 `codicefiscale_mismatch` with `confirmable: true`) */\n codicefiscale_confirmed?: boolean;\n /** The language of the page the person filled in (a platform language — `it`, `en`, …; any other tag is matched to the platform’s own: `en-GB` → `en`, `zh-TW` → `zh-Hant`). It decides the language of the mails that follow and becomes the preference of a NEW account; an existing account keeps its own. Unsupported values are ignored */\n locale?: string | null;\n /** The account terms (platform_terms) the person accepted on your site — optional, but when given it must name the in-force version */\n accept_terms?: LegalRef;\n /** The platform privacy notice (platform_privacy) the person read on your site — optional, same rule */\n acknowledge_privacy?: LegalRef;\n}\n\nexport interface EnrollRequest {\n email: string;\n first_name: string;\n last_name: string;\n /** Optional. A person is identified by a fiscal code OR by `dob` + `birthplace` + `birth_country` — never neither (422 `required` on each missing particular). When present it is validated and cross-checked against the names, the date and the place (the state, for people born abroad) */\n codicefiscale?: string | null;\n /** The person confirms a code that disagrees with their particulars (422 `codicefiscale_mismatch` with `confirmable: true`) */\n codicefiscale_confirmed?: boolean;\n /** Who holds parental responsibility for a minor (under 18 by `dob`). REQUIRED for a minor where the association declared it collects the block (`aps.collects_guardian_data`): 422 `required` on `guardian` otherwise; stored only where it declared so */\n guardian?: Guardian;\n /** Residence or, where different, domicile. Asked of every member or of nobody: the public profile says what the association declared (`member_address`: none — ignored, not stored · optional · required — 422 `required` on `address` without it) */\n address?: MemberAddress;\n phone?: string | null;\n dob?: string | null;\n /** Demographic only: it is not cross-checked */\n gender?: \"M\" | \"F\" | null;\n /** Comune (born in Italy) or city, free text (born abroad) */\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string | null;\n /** One of the association’s membership types (omit when it has exactly one) */\n membership_type?: string;\n /** The language of the page the person filled in (a platform language — `it`, `en`, …; any other tag is matched to the platform’s own: `en-GB` → `en`, `zh-TW` → `zh-Hant`). It decides the language of the mails that follow and becomes the preference of a NEW account; an existing account keeps its own. Unsupported values are ignored */\n locale?: string | null;\n /** The in-force statuto the person accepted on your site (from GET /v1/aps/{slug}) */\n accept_statuto: {\n version: number;\n sha256?: string;\n };\n /** The association's privacy notice the person read on your site (GET /v1/aps/{slug} → privacy_notice). REQUIRED when the association publishes one; 422 `privacy_notice_outdated` when it is not the in-force version */\n privacy_notice?: PrivacyNoticeAck;\n /** The account terms (platform_terms) the person accepted on your site — optional, must name the in-force version */\n accept_terms?: LegalRef;\n /** The platform privacy notice (platform_privacy) the person read — optional, same rule */\n acknowledge_privacy?: LegalRef;\n}\n\nexport interface Accepted {\n status: \"accepted\";\n}\n\nexport interface Me {\n /** The subject identifier of this person, as in the ID token */\n sub: string;\n email: string;\n email_verified: boolean;\n first_name?: string | null;\n last_name?: string | null;\n phone?: string | null;\n dob?: string | null;\n /** Demographic only */\n gender?: \"M\" | \"F\" | null;\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string | null;\n /** Optional: a person may have none */\n codicefiscale?: string | null;\n /** How the person is identified. `matched`: a fiscal code that agrees with their particulars; `mismatch_confirmed`: a code that disagrees, confirmed by the person; `absent`: no code — date, place and country of birth identify them; null: not identified yet (they cannot request a membership) */\n codicefiscale_check?: \"matched\" | \"mismatch_confirmed\" | \"absent\" | null;\n /** The language the person chose for the platform and its mails; null: never chosen — the language of the request, then of the association, applies */\n locale?: \"it\" | \"en\" | \"zh-Hans\" | \"zh-Hant\" | \"fr\" | \"es\" | \"de\" | \"pt-BR\" | null;\n updated_at?: string | null;\n}\n\nexport interface Guardian {\n first_name: string;\n last_name: string;\n /** Parent, guardian… as the association records it */\n relation: string;\n /** Optional; refused when malformed */\n codicefiscale?: string | null;\n email?: string | null;\n phone?: string | null;\n}\n\nexport interface MemberAddress {\n kind?: \"residence\" | \"domicile\";\n /** Street and number */\n line: string;\n postal_code?: string | null;\n city: string;\n /** Italian addresses only (two letters); dropped abroad */\n province?: string | null;\n /** ISO 3166-1 alpha-2 */\n country?: string;\n}\n\nexport interface EnrollConfirmRequest {\n token: string;\n /** Only after a 409 `identification_required`: what the account still lacks — a fiscal code, or date, place and country of birth. Completes the EMPTY fields of the profile, never over what is there */\n identification?: {\n dob?: string;\n birthplace?: string;\n birth_country?: string;\n codicefiscale?: string;\n codicefiscale_confirmed?: boolean;\n };\n /** Only after a 409 `address_required`: the association asks every member for an address (`member_address: required` on its public profile). Optional where it declared `optional`; ignored where it collects none */\n address?: MemberAddress;\n}\n\nexport interface Event {\n id?: string;\n slug?: string;\n /** The language the `title` was served in. When it is not the one you asked for, the association has no translation: you got its Italian text, not a machine translation */\n locale?: string;\n /** The languages in which this event has a title — the association’s own always, plus those it enabled and wrote */\n locales?: Array<string>;\n title?: string;\n summary?: string | null;\n /** Markdown; render it yourself */\n description_md?: string | null;\n starts_at?: string;\n ends_at?: string | null;\n timezone?: string;\n status?: \"published\" | \"completed\" | \"cancelled\";\n visibility?: \"members_only\" | \"public\";\n location?: {\n name?: string | null;\n address?: string | null;\n lat?: number | null;\n lng?: number | null;\n } | null;\n cover_url?: string | null;\n gallery?: Array<{\n url?: string;\n alt?: string | null;\n order?: number;\n }>;\n links?: Array<{\n label?: string;\n url?: string;\n }>;\n registration?: {\n opens_at?: string | null;\n closes_at?: string | null;\n capacity?: number | null;\n remaining?: number | null;\n cancellation_hours?: number;\n };\n registration_types?: Array<{\n uid?: string;\n cod?: string;\n name?: string;\n description?: string | null;\n /** 0 = free */\n amount?: number;\n currency?: string;\n quantity?: number | null;\n /** Places left (never who holds them) */\n remaining?: number | null;\n max_per_user?: number;\n requires_active_membership?: boolean;\n open?: boolean;\n reason?: \"sold_out\" | \"registration_not_open\" | \"registration_closed\" | null | null;\n opens_at?: string | null;\n closes_at?: string | null;\n }>;\n published_at?: string | null;\n cancelled_at?: string | null;\n cancel_reason?: string | null;\n}\n\nexport interface Registration {\n id?: string;\n status?: \"reserved\" | \"confirmed\" | \"cancelled\" | \"refunded\";\n event?: {\n id?: string;\n slug?: string;\n title?: string;\n starts_at?: string;\n ends_at?: string | null;\n timezone?: string;\n status?: string;\n location?: string | null;\n };\n registration_type?: {\n uid?: string;\n cod?: string;\n name?: string;\n amount?: number;\n currency?: string;\n };\n quantity?: number;\n reserved_until?: string | null;\n checked_in_at?: string | null;\n cancelled_at?: string | null;\n cancel_reason?: string | null;\n can_cancel?: boolean;\n payment?: {\n status?: string;\n amount?: number;\n currency?: string;\n method?: string;\n paid_at?: string;\n } | null;\n /** How to pay the contribution while reserved */\n payment_instructions?: string | null;\n /** Free text the person wrote. Withheld (null) from third-party clients when the association declared it processes special categories of data */\n note?: string | null;\n created_at?: string;\n /** The registration QR payload (vmt_…), confirmed registrations only */\n token?: string | null;\n}\n\nexport interface Eligibility {\n can_register?: boolean;\n membership_verdict?: string | null;\n types?: Array<{\n uid?: string;\n cod?: string;\n can_register?: boolean;\n reasons?: Array<string>;\n pending_membership?: boolean;\n }>;\n}\n\nexport interface RegistrationRequest {\n registration_type: string;\n note?: string | null;\n quantity?: number;\n /** The language the registration was made in (`it`, `en`): the language of the mails to a guest, and the fallback for a member who never chose one. Defaults to Accept-Language */\n locale?: string | null;\n}\n\nexport interface GuestRegistrationRequest {\n email: string;\n first_name: string;\n last_name: string;\n registration_type: string;\n note?: string | null;\n /** The language the registration was made in (`it`, `en`): the language of the mails to a guest, and the fallback for a member who never chose one. Defaults to Accept-Language */\n locale?: string | null;\n}\n\nexport interface RegistrationListItem {\n id?: string;\n status?: string;\n registration_type?: string | null;\n membership_id?: string | null;\n quantity?: number;\n checked_in_at?: string | null;\n created_at?: string;\n}\n\nexport interface LegalDocumentSummary {\n uid?: string;\n /** Document kind (platform_terms, platform_privacy, platform_cookie, aps_terms, aps_dpa, aps_dpa_annex1_processing … developer_terms) */\n kind: string;\n locale: \"it\" | \"en\" | \"zh-Hans\" | \"zh-Hant\" | \"fr\" | \"es\" | \"de\" | \"pt-BR\";\n /** Version label (1.0, 1.1, …) */\n version: string;\n title: string;\n /** What changed in this version */\n summary?: string | null;\n effective_from?: string | null;\n retired_at?: string | null;\n /** SHA-256 of the canonical template body */\n sha256?: string | null;\n /** This is the in-force version of the kind in its locale */\n current: boolean;\n requires_reacceptance?: boolean;\n}\n\nexport interface LegalDocumentList {\n documents: Array<LegalDocumentSummary>;\n /** Previous versions (with ?all=1) */\n archive?: Array<LegalDocumentSummary>;\n}\n\nexport type LegalDocument = unknown;\n\nexport interface SubProcessor {\n cod: string;\n name: string;\n entity?: string | null;\n service: string;\n data_categories?: string | null;\n location?: string | null;\n transfer_basis?: string | null;\n role: \"processor\" | \"controller\" | \"none\";\n status: \"active\" | \"planned\" | \"retired\";\n since?: string | null;\n until?: string | null;\n website?: string | null;\n}\n\nexport interface SubProcessorRegistry {\n /** The in-force Annex 3 version the registry is bound to */\n version?: string | null;\n effective_from?: string | null;\n notice_days?: number;\n at?: string;\n active: Array<SubProcessor>;\n planned: Array<SubProcessor>;\n /** Vendors that process no tenant data (transparency) */\n other: Array<SubProcessor>;\n}\n\nexport interface PrivacyNoticeRef {\n uid: string;\n version: number;\n locale: string;\n title?: string;\n sha256?: string | null;\n effective_from?: string | null;\n}\n\nexport type PrivacyNotice = unknown;\n\nexport interface LegalRef {\n /** The in-force version label shown (GET /v1/legal/{kind}) */\n version: string;\n /** Its template hash, when published */\n sha256?: string;\n}\n\nexport interface PrivacyNoticeAck {\n /** The in-force notice version shown (GET /v1/aps/{slug} → privacy_notice) */\n version: number;\n sha256?: string;\n /** The language of the notice you showed (`privacy_notice.locale` of the answer you read it from). Each language is its own document, with its own version: name it when you read the profile with `?locale=`. Default: the request’s `locale`, then the association’s language */\n locale?: string;\n}\n\nexport interface AcceptanceRecord {\n at: string;\n action: \"accepted\" | \"acknowledged\" | \"consented\" | \"withdrawn\" | \"declared\";\n channel?: \"ui\" | \"public\" | \"api\" | \"job\" | \"paper\";\n kind: string;\n title?: string;\n version: string;\n sha256?: string | null;\n /** Hash of the text actually shown */\n rendered_sha256?: string | null;\n locale?: string | null;\n /** The association the act concerns, when any */\n association?: string | null;\n}\n\nexport interface PendingDocument {\n kind: string;\n title?: string;\n locale?: string;\n version: string | number;\n sha256?: string | null;\n effective_from?: string | null;\n /** What the person is asked to do */\n action: \"accepted\" | \"acknowledged\" | \"consented\";\n /** Never acted on any version of this kind (false: a new version requires it again) */\n first?: boolean;\n}\n\nexport interface MyAcceptances {\n items: Array<AcceptanceRecord>;\n pending: {\n /** Account-layer documents still to accept / acknowledge */\n platform?: Array<PendingDocument>;\n /** This association's notice to members, when not yet acknowledged */\n privacy_notice?: PendingDocument | unknown;\n };\n}\n\nexport interface AcceptanceRequest {\n /** platform_terms | platform_privacy | network_consent | privacy_notice */\n kind: string;\n /** The in-force version shown */\n version: string | number;\n sha256?: string;\n}\n\nexport interface AcceptanceResult {\n recorded: boolean;\n kind: string;\n action: string;\n version: string;\n at: string;\n}\n\nexport interface EnrollConfirmResult {\n status: \"pending\" | \"active\" | \"suspended\" | \"revoked\" | \"rejected\";\n /** The person already had a membership request or membership here */\n already: boolean;\n /** Why the membership is still pending, in order: the association’s approval first (when it admits by decision of its board), then the fee. Empty when active */\n pending_reasons?: Array<\"approval\" | \"payment\">;\n /** May the fee be paid yet? False while the approval is pending: approval opens payment */\n payment_open?: boolean;\n /** When the card becomes usable, for an active membership inside the association’s usability delay; null otherwise */\n valid_from?: string | null;\n association: {\n name?: string;\n slug?: string;\n };\n /** Only for a link sent by the association’s hosted enrolment page when that page was opened from one of its public events: what became of the place the person asked for together with the request. `null` for every other link */\n event?: {\n slug?: string;\n title?: string;\n starts_at?: string;\n timezone?: string;\n place?: string | null;\n registration_type?: {\n uid?: string;\n name?: string;\n /** 0 = free */\n amount?: number;\n currency?: string;\n };\n /** `confirmed`: the place is theirs. `reserved`: held, see `waiting`. `held`: the membership request itself still waits for the address to be confirmed, and no place was asked for. `unavailable`: no place, see `reasons` */\n state?: \"confirmed\" | \"reserved\" | \"held\" | \"unavailable\";\n /** What a `reserved` place waits for: the membership to become active (it is then confirmed by itself when free), the contribution, or both */\n waiting?: Array<\"membership\" | \"contribution\">;\n /** Why the place is `unavailable`: the reasons of `GET /v1/events/{slug}/eligibility` */\n reasons?: Array<string>;\n reserved_until?: string | null;\n /** How to pay a contribution that is owed, in the association’s words */\n payment_instructions?: string | null;\n /** The person held this place before the link was used */\n already?: boolean;\n } | null;\n}\n\n/** Every operation of the document: id → [method, path]. */\nexport const operations = {\n getOpenApi: ['GET', '/v1/openapi.json'],\n getCardKeys: ['GET', '/v1/card-keys'],\n getApsPublicConfig: ['GET', '/v1/aps/{slug}'],\n verifyCard: ['GET', '/v1/verify/{card_token}'],\n validateFiscalCode: ['POST', '/v1/validate/fiscal-code'],\n oauthToken: ['POST', '/v1/oauth/token'],\n oauthRevoke: ['POST', '/v1/oauth/revoke'],\n oauthClientInfo: ['GET', '/v1/oauth/client-info'],\n getMe: ['GET', '/v1/me'],\n closeMe: ['DELETE', '/v1/me'],\n updateMe: ['PATCH', '/v1/me'],\n exportMe: ['GET', '/v1/me/export'],\n getMyMembership: ['GET', '/v1/me/membership'],\n requestMyMembership: ['POST', '/v1/me/membership'],\n renewMyMembership: ['POST', '/v1/me/membership/renew'],\n setNetworkOptIn: ['PATCH', '/v1/me/membership/network-opt-in'],\n getMyCardImage: ['GET', '/v1/me/membership/card.svg'],\n emailMyCard: ['POST', '/v1/me/membership/card/email'],\n getGoogleWalletLink: ['GET', '/v1/me/membership/wallet/google'],\n getMyMembershipEvents: ['GET', '/v1/me/membership/events'],\n getMyStatuto: ['GET', '/v1/me/membership/statuto'],\n acceptMyStatuto: ['POST', '/v1/me/membership/statuto/accept'],\n getMyAcceptances: ['GET', '/v1/me/acceptances'],\n recordMyAcceptance: ['POST', '/v1/me/acceptances'],\n getMyCard: ['GET', '/v1/me/membership/card'],\n getMyConnections: ['GET', '/v1/me/connections'],\n revokeMyConnection: ['DELETE', '/v1/me/connections/{client_id}'],\n listMemberships: ['GET', '/v1/memberships'],\n getMembershipStatus: ['GET', '/v1/memberships/{id}/status'],\n getSandbox: ['GET', '/v1/sandbox'],\n resetSandbox: ['POST', '/v1/sandbox/reset'],\n signup: ['POST', '/v1/signup'],\n enroll: ['POST', '/v1/enroll'],\n confirmEnrollment: ['POST', '/v1/enroll/confirm'],\n createCheckin: ['POST', '/v1/checkins'],\n listPublicEvents: ['GET', '/v1/aps/{slug}/events'],\n getPublicEvent: ['GET', '/v1/aps/{slug}/events/{event}'],\n listEvents: ['GET', '/v1/events'],\n getEvent: ['GET', '/v1/events/{slug}'],\n getEventEligibility: ['GET', '/v1/events/{slug}/eligibility'],\n createRegistration: ['POST', '/v1/events/{slug}/registrations'],\n listEventRegistrations: ['GET', '/v1/events/{slug}/registrations'],\n listMyRegistrations: ['GET', '/v1/me/registrations'],\n getMyRegistration: ['GET', '/v1/me/registrations/{id}'],\n cancelMyRegistration: ['DELETE', '/v1/me/registrations/{id}'],\n createGuestRegistration: ['POST', '/v1/events/{slug}/registrations/guest'],\n confirmGuestRegistration: ['POST', '/v1/registrations/confirm'],\n viewGuestRegistration: ['POST', '/v1/registrations/view'],\n listLegalDocuments: ['GET', '/v1/legal'],\n getSubProcessors: ['GET', '/v1/legal/sub-processors'],\n getLegalDocument: ['GET', '/v1/legal/{kind}'],\n getApsPrivacyNotice: ['GET', '/v1/aps/{slug}/privacy-notice'],\n getApsStatuto: ['GET', '/v1/aps/{slug}/statuto'],\n} as const;\nexport type OperationId = keyof typeof operations;\n"]}
1
+ {"version":3,"file":"generated.js","sourceRoot":"","sources":["../src/generated.ts"],"names":[],"mappings":"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","sourcesContent":["// GENERATED by scripts/gen-types.mjs from openapi/v1.json — do not edit. Regenerate: npm run spec:types\n// Spec version 2026-10-29 · 48 paths · 37 schemas\n\nexport interface Problem {\n type: string;\n title: string;\n status: number;\n detail?: string;\n code: string;\n request_id?: string;\n errors?: Array<{\n field?: string;\n code?: string;\n message?: string;\n }>;\n}\n\nexport interface Verification {\n status: \"active\" | \"inactive\";\n valid_until?: string;\n /** With `reason: not_yet_valid`: the card is genuine and active, and becomes usable at this moment */\n valid_from?: string;\n reason?: \"expired\" | \"invalid\" | \"not_yet_valid\";\n /** Present for registration tokens */\n kind?: \"card\" | \"registration\";\n event?: {\n slug?: string;\n starts_at?: string;\n } | null;\n}\n\nexport interface MembershipType {\n uid?: string;\n cod?: string;\n name?: string;\n description?: string | null;\n quota_amount?: number | null;\n currency?: string;\n expiry_model?: \"solar_year\" | \"rolling_12\" | \"rolling_24\" | \"prorated_solar\" | \"custom\";\n network_eligible?: boolean;\n}\n\nexport interface Statuto {\n aps?: {\n slug?: string;\n name?: string;\n };\n title: string;\n version: number;\n approved_on?: string | null;\n /** Of the uploaded document, when there is one */\n sha256?: string | null;\n /** The text as registered; empty when only a document was uploaded */\n content_md?: string;\n content_html: string;\n /** The uploaded document, a link valid for 15 minutes */\n document_url?: string | null;\n}\n\nexport interface ApsPublicConfig {\n /** The language this answer is written in */\n locale?: string;\n /** The languages the association offers: its own, plus those it enabled */\n locales?: Array<string>;\n aps: {\n slug?: string;\n name?: string;\n picture_url?: string | null;\n citta?: string | null;\n provincia?: string | null;\n /** The association's own website (http or https), or null when it gave none */\n website?: string | null;\n enroll_enabled?: boolean;\n /** Whether a membership request would be taken now: enrolment on, a member more fits the plan, the association ready to collect requests, and its public door open. */\n accepting_requests?: boolean;\n /** True while Vimine registers people by invitation only (the private beta) and this association takes only the people it invited: `accepting_requests` is then false, and `POST /v1/enroll` answers 403 `not_available`. */\n invitation_only?: boolean;\n /** True for a sandbox: the test copy of an association that test clients work on, with synthetic members only. It never sends e-mail, takes no payments and is never in the Network. */\n sandbox?: boolean;\n /** How the association admits its members, so that an applicant can be told up front what to expect. `model`: `board` — the request waits for a decision of the association’s board, and any fee is paid after it; `provisional` — admitted at once, ratified by the board later; `automatic` — active as soon as the conditions are met. `delay_hours`: the hours between admission and a USABLE card (0 = at once): the membership is active from admission, the card counts at the door only afterwards (see `valid_from`). */\n admission?: {\n model?: \"board\" | \"provisional\" | \"automatic\";\n delay_hours?: number;\n };\n /** Kept for compatibility: true when `admission.model` is `board`. Read `admission` instead. */\n approval_required?: boolean;\n /** Whether the association collects its members’ address — of every member or of nobody. `none`: do not ask (an `address` sent anyway is not stored); `optional`; `required`: enrolment answers 422 without one. */\n member_address?: \"none\" | \"optional\" | \"required\";\n /** How to pay the fee, as the association words it */\n payment_instructions?: string | null;\n /** The activities of general interest the association carries out (Italian Third Sector Code, art. 5): `cod` is the letter of the article, `description` its Italian wording; one is marked as prevalent. */\n activity_sectors?: Array<{\n cod?: string;\n description?: string;\n prevalent?: boolean;\n }>;\n /** Present when the association is registered in the RUNTS (the Italian national register of Third Sector entities), as checked by the platform against the official public lists; null otherwise. Never typed by the association. */\n registry?: {\n /** Section of the register */\n section?: \"APS\" | \"ODV\" | \"EF\" | \"IS\" | \"RA\" | \"SOMS\" | \"ALTRI\" | null | null;\n /** Repertory number */\n number?: string | null;\n registered_on?: string | null;\n /** Date of the official list the check ran against */\n checked_on?: string | null;\n } | null;\n };\n membership_types: Array<MembershipType>;\n statuto: Statuto | unknown;\n /** The association's in-force privacy notice to members (full text: GET /v1/aps/{slug}/privacy-notice) */\n privacy_notice?: PrivacyNoticeRef | unknown;\n}\n\nexport interface FiscalCodeCheck {\n /** Codice fiscale (16 characters) */\n code: string;\n first_name?: string;\n last_name?: string;\n gender?: \"M\" | \"F\";\n /** Date of birth */\n date?: string;\n /** Birthplace: the comune, for a person born in Italy */\n place?: string;\n /** Birth country, ISO 3166-1 alpha-2. A code encodes the comune for people born in Italy and only the STATE for everybody else: anything but IT is compared with that state and `place` is ignored */\n country?: string;\n}\n\nexport interface FiscalCodeResult {\n valid?: boolean;\n error?: \"invalid\" | \"mismatch\" | null;\n /** What disagrees with the code, when `error` is `mismatch` */\n mismatches?: Array<\"lastName\" | \"firstName\" | \"gender\" | \"date\" | \"place\">;\n /** `names_swapped`: the code matches once surname and given name are exchanged */\n hints?: Array<\"names_swapped\">;\n /** The date of birth the code itself encodes */\n birth_date?: string | null;\n /** The birth country the code itself encodes, ISO 3166-1 alpha-2 (IT for a comune) */\n birth_country?: string | null;\n}\n\nexport interface CardKeys {\n keys?: Array<{\n kty?: string;\n crv?: string;\n x?: string;\n kid?: string;\n use?: string;\n alg?: string;\n }>;\n}\n\nexport interface SignupRequest {\n email: string;\n first_name: string;\n last_name: string;\n phone?: string | null;\n dob?: string | null;\n /** Demographic only: it is not cross-checked */\n gender?: \"M\" | \"F\" | null;\n /** Comune (born in Italy) or city, free text (born abroad) */\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string | null;\n /** Validated and cross-checked against the other fields when present */\n codicefiscale?: string | null;\n /** The person confirms a code that disagrees with their particulars (422 `codicefiscale_mismatch` with `confirmable: true`) */\n codicefiscale_confirmed?: boolean;\n /** The language of the page the person filled in (a platform language — `it`, `en`, …; any other tag is matched to the platform’s own: `en-GB` → `en`, `zh-TW` → `zh-Hant`). It decides the language of the mails that follow and becomes the preference of a NEW account; an existing account keeps its own. Unsupported values are ignored */\n locale?: string | null;\n /** The account terms (platform_terms) the person accepted on your site — optional, but when given it must name the in-force version */\n accept_terms?: LegalRef;\n /** The platform privacy notice (platform_privacy) the person read on your site — optional, same rule */\n acknowledge_privacy?: LegalRef;\n}\n\nexport interface EnrollRequest {\n email: string;\n first_name: string;\n last_name: string;\n /** Optional. A person is identified by a fiscal code OR by `dob` + `birthplace` + `birth_country` — never neither (422 `required` on each missing particular). When present it is validated and cross-checked against the names, the date and the place (the state, for people born abroad) */\n codicefiscale?: string | null;\n /** The person confirms a code that disagrees with their particulars (422 `codicefiscale_mismatch` with `confirmable: true`) */\n codicefiscale_confirmed?: boolean;\n /** Who holds parental responsibility for a minor (under 18 by `dob`). REQUIRED for a minor where the association declared it collects the block (`aps.collects_guardian_data`): 422 `required` on `guardian` otherwise; stored only where it declared so */\n guardian?: Guardian;\n /** Residence or, where different, domicile. Asked of every member or of nobody: the public profile says what the association declared (`member_address`: none — ignored, not stored · optional · required — 422 `required` on `address` without it) */\n address?: MemberAddress;\n phone?: string | null;\n dob?: string | null;\n /** Demographic only: it is not cross-checked */\n gender?: \"M\" | \"F\" | null;\n /** Comune (born in Italy) or city, free text (born abroad) */\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string | null;\n /** One of the association’s membership types (omit when it has exactly one) */\n membership_type?: string;\n /** The language of the page the person filled in (a platform language — `it`, `en`, …; any other tag is matched to the platform’s own: `en-GB` → `en`, `zh-TW` → `zh-Hant`). It decides the language of the mails that follow and becomes the preference of a NEW account; an existing account keeps its own. Unsupported values are ignored */\n locale?: string | null;\n /** The in-force statuto the person accepted on your site (from GET /v1/aps/{slug}) */\n accept_statuto: {\n version: number;\n sha256?: string;\n };\n /** The association's privacy notice the person read on your site (GET /v1/aps/{slug} → privacy_notice). REQUIRED when the association publishes one; 422 `privacy_notice_outdated` when it is not the in-force version */\n privacy_notice?: PrivacyNoticeAck;\n /** The account terms (platform_terms) the person accepted on your site — optional, must name the in-force version */\n accept_terms?: LegalRef;\n /** The platform privacy notice (platform_privacy) the person read — optional, same rule */\n acknowledge_privacy?: LegalRef;\n}\n\nexport interface Accepted {\n status: \"accepted\";\n}\n\nexport interface Me {\n /** The subject identifier of this person, as in the ID token */\n sub: string;\n email: string;\n email_verified: boolean;\n first_name?: string | null;\n last_name?: string | null;\n phone?: string | null;\n dob?: string | null;\n /** Demographic only */\n gender?: \"M\" | \"F\" | null;\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string | null;\n /** Optional: a person may have none */\n codicefiscale?: string | null;\n /** How the person is identified. `matched`: a fiscal code that agrees with their particulars; `mismatch_confirmed`: a code that disagrees, confirmed by the person; `absent`: no code — date, place and country of birth identify them; null: not identified yet (they cannot request a membership) */\n codicefiscale_check?: \"matched\" | \"mismatch_confirmed\" | \"absent\" | null;\n /** The language the person chose for the platform and its mails; null: never chosen — the language of the request, then of the association, applies */\n locale?: \"it\" | \"en\" | \"zh-Hans\" | \"zh-Hant\" | \"fr\" | \"es\" | \"de\" | \"pt-BR\" | null;\n updated_at?: string | null;\n}\n\nexport interface Guardian {\n first_name: string;\n last_name: string;\n /** Parent, guardian… as the association records it */\n relation: string;\n /** Optional; refused when malformed */\n codicefiscale?: string | null;\n email?: string | null;\n phone?: string | null;\n}\n\nexport interface MemberAddress {\n kind?: \"residence\" | \"domicile\";\n /** Street and number */\n line: string;\n postal_code?: string | null;\n city: string;\n /** Italian addresses only (two letters); dropped abroad */\n province?: string | null;\n /** ISO 3166-1 alpha-2 */\n country?: string;\n}\n\nexport interface EnrollConfirmRequest {\n token: string;\n /** Only after a 409 `identification_required`: what the account still lacks — a fiscal code, or date, place and country of birth. Completes the EMPTY fields of the profile, never over what is there */\n identification?: {\n dob?: string;\n birthplace?: string;\n birth_country?: string;\n codicefiscale?: string;\n codicefiscale_confirmed?: boolean;\n };\n /** Only after a 409 `address_required`: the association asks every member for an address (`member_address: required` on its public profile). Optional where it declared `optional`; ignored where it collects none */\n address?: MemberAddress;\n}\n\nexport interface Event {\n id?: string;\n slug?: string;\n /** The language the `title` was served in. When it is not the one you asked for, the association has no translation: you got its Italian text, not a machine translation */\n locale?: string;\n /** The languages in which this event has a title — the association’s own always, plus those it enabled and wrote */\n locales?: Array<string>;\n title?: string;\n summary?: string | null;\n /** Markdown; render it yourself */\n description_md?: string | null;\n starts_at?: string;\n ends_at?: string | null;\n timezone?: string;\n status?: \"published\" | \"completed\" | \"cancelled\";\n visibility?: \"members_only\" | \"public\";\n location?: {\n name?: string | null;\n address?: string | null;\n lat?: number | null;\n lng?: number | null;\n } | null;\n cover_url?: string | null;\n gallery?: Array<{\n url?: string;\n alt?: string | null;\n order?: number;\n }>;\n links?: Array<{\n label?: string;\n url?: string;\n }>;\n registration?: {\n opens_at?: string | null;\n closes_at?: string | null;\n capacity?: number | null;\n remaining?: number | null;\n cancellation_hours?: number;\n };\n registration_types?: Array<{\n uid?: string;\n cod?: string;\n name?: string;\n description?: string | null;\n /** 0 = free */\n amount?: number;\n currency?: string;\n quantity?: number | null;\n /** Places left (never who holds them) */\n remaining?: number | null;\n max_per_user?: number;\n requires_active_membership?: boolean;\n open?: boolean;\n reason?: \"sold_out\" | \"registration_not_open\" | \"registration_closed\" | null | null;\n opens_at?: string | null;\n closes_at?: string | null;\n }>;\n published_at?: string | null;\n cancelled_at?: string | null;\n cancel_reason?: string | null;\n}\n\nexport interface Registration {\n id?: string;\n status?: \"reserved\" | \"confirmed\" | \"cancelled\" | \"refunded\";\n event?: {\n id?: string;\n slug?: string;\n title?: string;\n starts_at?: string;\n ends_at?: string | null;\n timezone?: string;\n status?: string;\n location?: string | null;\n };\n registration_type?: {\n uid?: string;\n cod?: string;\n name?: string;\n amount?: number;\n currency?: string;\n };\n quantity?: number;\n reserved_until?: string | null;\n checked_in_at?: string | null;\n cancelled_at?: string | null;\n cancel_reason?: string | null;\n can_cancel?: boolean;\n payment?: {\n status?: string;\n amount?: number;\n currency?: string;\n method?: string;\n paid_at?: string;\n } | null;\n /** How to pay the contribution while reserved */\n payment_instructions?: string | null;\n /** Free text the person wrote. Withheld (null) from third-party clients when the association declared it processes special categories of data */\n note?: string | null;\n created_at?: string;\n /** The registration QR payload (vmt_…), confirmed registrations only */\n token?: string | null;\n}\n\nexport interface Eligibility {\n can_register?: boolean;\n membership_verdict?: string | null;\n types?: Array<{\n uid?: string;\n cod?: string;\n can_register?: boolean;\n reasons?: Array<string>;\n pending_membership?: boolean;\n }>;\n}\n\nexport interface RegistrationRequest {\n registration_type: string;\n note?: string | null;\n quantity?: number;\n /** The language the registration was made in (`it`, `en`): the language of the mails to a guest, and the fallback for a member who never chose one. Defaults to Accept-Language */\n locale?: string | null;\n}\n\nexport interface GuestRegistrationRequest {\n email: string;\n first_name: string;\n last_name: string;\n registration_type: string;\n note?: string | null;\n /** The language the registration was made in (`it`, `en`): the language of the mails to a guest, and the fallback for a member who never chose one. Defaults to Accept-Language */\n locale?: string | null;\n}\n\nexport interface RegistrationListItem {\n id?: string;\n status?: string;\n registration_type?: string | null;\n membership_id?: string | null;\n quantity?: number;\n checked_in_at?: string | null;\n created_at?: string;\n}\n\nexport interface LegalDocumentSummary {\n uid?: string;\n /** Document kind (platform_terms, platform_privacy, platform_cookie, aps_terms, aps_dpa, aps_dpa_annex1_processing … developer_terms) */\n kind: string;\n locale: \"it\" | \"en\" | \"zh-Hans\" | \"zh-Hant\" | \"fr\" | \"es\" | \"de\" | \"pt-BR\";\n /** Version label (1.0, 1.1, …) */\n version: string;\n title: string;\n /** What changed in this version */\n summary?: string | null;\n effective_from?: string | null;\n retired_at?: string | null;\n /** SHA-256 of the canonical template body */\n sha256?: string | null;\n /** This is the in-force version of the kind in its locale */\n current: boolean;\n requires_reacceptance?: boolean;\n}\n\nexport interface LegalDocumentList {\n documents: Array<LegalDocumentSummary>;\n /** Previous versions (with ?all=1) */\n archive?: Array<LegalDocumentSummary>;\n}\n\nexport type LegalDocument = unknown;\n\nexport interface SubProcessor {\n cod: string;\n name: string;\n entity?: string | null;\n service: string;\n data_categories?: string | null;\n location?: string | null;\n transfer_basis?: string | null;\n role: \"processor\" | \"controller\" | \"none\";\n status: \"active\" | \"planned\" | \"retired\";\n since?: string | null;\n until?: string | null;\n website?: string | null;\n}\n\nexport interface SubProcessorRegistry {\n /** The in-force Annex 3 version the registry is bound to */\n version?: string | null;\n effective_from?: string | null;\n notice_days?: number;\n at?: string;\n active: Array<SubProcessor>;\n planned: Array<SubProcessor>;\n /** Vendors that process no tenant data (transparency) */\n other: Array<SubProcessor>;\n}\n\nexport interface PrivacyNoticeRef {\n uid: string;\n version: number;\n locale: string;\n title?: string;\n sha256?: string | null;\n effective_from?: string | null;\n}\n\nexport type PrivacyNotice = unknown;\n\nexport interface Regolamento {\n aps?: {\n slug?: string;\n name?: string;\n };\n uid: string;\n version: number;\n locale: string;\n /** The association's own title for it */\n title: string;\n effective_from?: string | null;\n sha256?: string | null;\n rendered_sha256?: string;\n content_md: string;\n content_html: string;\n}\n\nexport interface LegalRef {\n /** The in-force version label shown (GET /v1/legal/{kind}) */\n version: string;\n /** Its template hash, when published */\n sha256?: string;\n}\n\nexport interface PrivacyNoticeAck {\n /** The in-force notice version shown (GET /v1/aps/{slug} → privacy_notice) */\n version: number;\n sha256?: string;\n /** The language of the notice you showed (`privacy_notice.locale` of the answer you read it from). Each language is its own document, with its own version: name it when you read the profile with `?locale=`. Default: the request’s `locale`, then the association’s language */\n locale?: string;\n}\n\nexport interface AcceptanceRecord {\n at: string;\n action: \"accepted\" | \"acknowledged\" | \"consented\" | \"withdrawn\" | \"declared\";\n channel?: \"ui\" | \"public\" | \"api\" | \"job\" | \"paper\";\n kind: string;\n title?: string;\n version: string;\n sha256?: string | null;\n /** Hash of the text actually shown */\n rendered_sha256?: string | null;\n locale?: string | null;\n /** The association the act concerns, when any */\n association?: string | null;\n}\n\nexport interface PendingDocument {\n kind: string;\n title?: string;\n locale?: string;\n version: string | number;\n sha256?: string | null;\n effective_from?: string | null;\n /** What the person is asked to do */\n action: \"accepted\" | \"acknowledged\" | \"consented\";\n /** Never acted on any version of this kind (false: a new version requires it again) */\n first?: boolean;\n}\n\nexport interface MyAcceptances {\n items: Array<AcceptanceRecord>;\n pending: {\n /** Account-layer documents still to accept / acknowledge */\n platform?: Array<PendingDocument>;\n /** This association's notice to members, when not yet acknowledged */\n privacy_notice?: PendingDocument | unknown;\n };\n}\n\nexport interface AcceptanceRequest {\n /** platform_terms | platform_privacy | network_consent | privacy_notice */\n kind: string;\n /** The in-force version shown */\n version: string | number;\n sha256?: string;\n}\n\nexport interface AcceptanceResult {\n recorded: boolean;\n kind: string;\n action: string;\n version: string;\n at: string;\n}\n\nexport interface EnrollConfirmResult {\n status: \"pending\" | \"active\" | \"suspended\" | \"revoked\" | \"rejected\";\n /** The person already had a membership request or membership here */\n already: boolean;\n /** Why the membership is still pending, in order: the association’s approval first (when it admits by decision of its board), then the fee. Empty when active */\n pending_reasons?: Array<\"approval\" | \"payment\">;\n /** May the fee be paid yet? False while the approval is pending: approval opens payment */\n payment_open?: boolean;\n /** When the card becomes usable, for an active membership inside the association’s usability delay; null otherwise */\n valid_from?: string | null;\n association: {\n name?: string;\n slug?: string;\n };\n /** Only for a link sent by the association’s hosted enrolment page when that page was opened from one of its public events: what became of the place the person asked for together with the request. `null` for every other link */\n event?: {\n slug?: string;\n title?: string;\n starts_at?: string;\n timezone?: string;\n place?: string | null;\n registration_type?: {\n uid?: string;\n name?: string;\n /** 0 = free */\n amount?: number;\n currency?: string;\n };\n /** `confirmed`: the place is theirs. `reserved`: held, see `waiting`. `held`: the membership request itself still waits for the address to be confirmed, and no place was asked for. `unavailable`: no place, see `reasons` */\n state?: \"confirmed\" | \"reserved\" | \"held\" | \"unavailable\";\n /** What a `reserved` place waits for: the membership to become active (it is then confirmed by itself when free), the contribution, or both */\n waiting?: Array<\"membership\" | \"contribution\">;\n /** Why the place is `unavailable`: the reasons of `GET /v1/events/{slug}/eligibility` */\n reasons?: Array<string>;\n reserved_until?: string | null;\n /** How to pay a contribution that is owed, in the association’s words */\n payment_instructions?: string | null;\n /** The person held this place before the link was used */\n already?: boolean;\n } | null;\n}\n\n/** Every operation of the document: id → [method, path]. */\nexport const operations = {\n getOpenApi: ['GET', '/v1/openapi.json'],\n getCardKeys: ['GET', '/v1/card-keys'],\n getApsPublicConfig: ['GET', '/v1/aps/{slug}'],\n verifyCard: ['GET', '/v1/verify/{card_token}'],\n validateFiscalCode: ['POST', '/v1/validate/fiscal-code'],\n oauthToken: ['POST', '/v1/oauth/token'],\n oauthRevoke: ['POST', '/v1/oauth/revoke'],\n oauthClientInfo: ['GET', '/v1/oauth/client-info'],\n getMe: ['GET', '/v1/me'],\n closeMe: ['DELETE', '/v1/me'],\n updateMe: ['PATCH', '/v1/me'],\n exportMe: ['GET', '/v1/me/export'],\n getMyMembership: ['GET', '/v1/me/membership'],\n requestMyMembership: ['POST', '/v1/me/membership'],\n renewMyMembership: ['POST', '/v1/me/membership/renew'],\n setNetworkOptIn: ['PATCH', '/v1/me/membership/network-opt-in'],\n getMyCardImage: ['GET', '/v1/me/membership/card.svg'],\n emailMyCard: ['POST', '/v1/me/membership/card/email'],\n getGoogleWalletLink: ['GET', '/v1/me/membership/wallet/google'],\n getMyMembershipEvents: ['GET', '/v1/me/membership/events'],\n getMyStatuto: ['GET', '/v1/me/membership/statuto'],\n acceptMyStatuto: ['POST', '/v1/me/membership/statuto/accept'],\n getMyAcceptances: ['GET', '/v1/me/acceptances'],\n recordMyAcceptance: ['POST', '/v1/me/acceptances'],\n getMyCard: ['GET', '/v1/me/membership/card'],\n getMyConnections: ['GET', '/v1/me/connections'],\n revokeMyConnection: ['DELETE', '/v1/me/connections/{client_id}'],\n listMemberships: ['GET', '/v1/memberships'],\n getMembershipStatus: ['GET', '/v1/memberships/{id}/status'],\n getSandbox: ['GET', '/v1/sandbox'],\n resetSandbox: ['POST', '/v1/sandbox/reset'],\n signup: ['POST', '/v1/signup'],\n enroll: ['POST', '/v1/enroll'],\n confirmEnrollment: ['POST', '/v1/enroll/confirm'],\n createCheckin: ['POST', '/v1/checkins'],\n listPublicEvents: ['GET', '/v1/aps/{slug}/events'],\n getPublicEvent: ['GET', '/v1/aps/{slug}/events/{event}'],\n listEvents: ['GET', '/v1/events'],\n getEvent: ['GET', '/v1/events/{slug}'],\n getEventEligibility: ['GET', '/v1/events/{slug}/eligibility'],\n createRegistration: ['POST', '/v1/events/{slug}/registrations'],\n listEventRegistrations: ['GET', '/v1/events/{slug}/registrations'],\n listMyRegistrations: ['GET', '/v1/me/registrations'],\n getMyRegistration: ['GET', '/v1/me/registrations/{id}'],\n cancelMyRegistration: ['DELETE', '/v1/me/registrations/{id}'],\n createGuestRegistration: ['POST', '/v1/events/{slug}/registrations/guest'],\n confirmGuestRegistration: ['POST', '/v1/registrations/confirm'],\n viewGuestRegistration: ['POST', '/v1/registrations/view'],\n listLegalDocuments: ['GET', '/v1/legal'],\n getSubProcessors: ['GET', '/v1/legal/sub-processors'],\n getLegalDocument: ['GET', '/v1/legal/{kind}'],\n getApsPrivacyNotice: ['GET', '/v1/aps/{slug}/privacy-notice'],\n getApsRegolamento: ['GET', '/v1/aps/{slug}/regolamento'],\n getApsStatuto: ['GET', '/v1/aps/{slug}/statuto'],\n} as const;\nexport type OperationId = keyof typeof operations;\n"]}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type PublicApi } from './public.js';
2
2
  import { type StorageKind, type TokenStorage } from './storage.js';
3
- import type { AcceptanceInput, AcceptanceResult, Accepted, Card, Connection, Eligibility, Event, EventList, EventListParams, Locale, LocaleParam, Me, Membership, MembershipEvents, MembershipRequest, MembershipRequestResult, MeUpdate, MyAcceptances, NetworkOptIn, Registration, RegistrationList, RegistrationRequest, RenewResult, Scope, StatutoAccept, StatutoInfo } from './types.js';
3
+ import type { AcceptanceInput, AcceptanceResult, Accepted, AssociationRef, Card, Connection, Eligibility, Event, EventList, EventListParams, Locale, LocaleParam, Me, Membership, MembershipEvents, MembershipRequest, MembershipRequestResult, MeUpdate, MyAcceptances, NetworkOptIn, Registration, RegistrationList, RegistrationRequest, RenewResult, Scope, StatutoAccept, StatutoInfo } from './types.js';
4
4
  export { VimineError } from './errors.js';
5
5
  export type { FieldError, ProblemDetails } from './errors.js';
6
6
  export { createPkce, createState, createVerifier, createChallenge, base64url } from './pkce.js';
@@ -49,6 +49,8 @@ export interface Session {
49
49
  sub: string | null;
50
50
  /** `test` for sessions minted through a sandbox client. */
51
51
  mode?: 'live' | 'test';
52
+ /** The association the member signed in to (name and picture, to show beside them); null from an API that predates it. */
53
+ aps?: AssociationRef | null;
52
54
  }
53
55
  export interface RedirectResult {
54
56
  session: Session;
package/dist/index.js CHANGED
@@ -341,7 +341,8 @@ export class Vimine {
341
341
  expiresAt: Date.now() + Math.max(0, tokens.expires_in) * 1000,
342
342
  scope: String(tokens.scope || '').split(/\s+/).filter(Boolean),
343
343
  sub: tokens.sub ?? (typeof claims?.sub === 'string' ? claims.sub : null),
344
- mode: claims?.mode === 'test' ? 'test' : 'live'
344
+ mode: claims?.mode === 'test' ? 'test' : 'live',
345
+ aps: tokens.aps ?? this.getSession()?.aps ?? null
345
346
  };
346
347
  this.storage.set(this.keys.session, JSON.stringify(session));
347
348
  this.emit(session);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// @vimine/sdk — Sign in with Vimine (OAuth 2.1 + PKCE) and the member API, for websites and apps of\n// associations on vimine.network. Zero dependencies; browser-first (WebCrypto, fetch), also fine in Node ≥ 18\n// with a storage of your choice.\n//\n// const mp = new Vimine({ clientId: 'vmc_…', redirectUri: 'https://www.example.org/callback' });\n// await mp.signIn(); // → the hosted sign-in + consent page, then back to redirectUri\n// await mp.handleRedirect(); // on the callback page: exchanges the code, stores the session\n// const membership = await mp.membership.get();\n//\n// The member's password is never typed into your page: sign-in happens on vimine.network, your site only ever\n// holds tokens for the permissions the member granted.\nimport { VimineError } from './errors.js';\nimport { createPkce, createState } from './pkce.js';\nimport { DEFAULT_API_URL, eventQuery, jsonOrThrow, localeQuery, publicApi, withNetworkError, type PublicApi } from './public.js';\nimport { resolveStorage, type StorageKind, type TokenStorage } from './storage.js';\nimport type {\n AcceptanceInput,\n AcceptanceResult,\n Accepted,\n Card,\n Connection,\n Eligibility,\n Event,\n EventList,\n EventListParams,\n Locale,\n LocaleParam,\n Me,\n Membership,\n MembershipEvents,\n MembershipRequest,\n MembershipRequestResult,\n MeUpdate,\n MyAcceptances,\n NetworkOptIn,\n Registration,\n RegistrationList,\n RegistrationRequest,\n RenewResult,\n Scope,\n StatutoAccept,\n StatutoInfo,\n TokenResponse\n} from './types.js';\n\nexport { VimineError } from './errors.js';\nexport type { FieldError, ProblemDetails } from './errors.js';\nexport { createPkce, createState, createVerifier, createChallenge, base64url } from './pkce.js';\nexport { MemoryStorage, type StorageKind, type TokenStorage } from './storage.js';\n/** The OpenAPI document's own vocabulary (generated from openapi/v1.json — `npm run spec:types`). */\nexport type * as Spec from './generated.js';\nexport { publicApi, DEFAULT_API_URL, eventQuery, type PublicApi, type PublicOptions } from './public.js';\nexport type * from './types.js';\n\nexport const DEFAULT_APP_URL = 'https://app.vimine.network';\n/** Refresh this long before the access token expires. */\nconst REFRESH_LEAD_MS = 30_000;\n\nexport interface VimineOptions {\n /** Your client id (`vmc_…`), from the association's developer console. */\n clientId: string;\n /** One of the redirect URIs registered for the client — the page that calls `handleRedirect()`. */\n redirectUri: string;\n /** Default permissions to ask for; `signIn()` may override. */\n scopes?: Scope[];\n /** The API origin (default production). */\n apiUrl?: string;\n /** The app origin that hosts sign-in and consent (default production). */\n appUrl?: string;\n /** Where tokens live: `session` (default, per tab), `local` (shared across tabs), `memory`, or your own adapter. */\n storage?: StorageKind | TokenStorage;\n /** Storage key prefix (default derived from the client id). */\n storageKey?: string;\n /** UI language of the hosted pages (a platform language; Chinese by script: `zh-Hans`, `zh-Hant`). */\n locale?: Locale;\n /** Custom fetch (tests, polyfills). */\n fetch?: typeof fetch;\n /** How to leave the page (default: the top window's `location.assign`). */\n navigate?: (url: string) => void;\n}\n\nexport interface SignInOptions {\n scopes?: Scope[];\n /** `login` forces the credential form even with a live session; `consent` forces the consent screen. */\n prompt?: 'login' | 'consent';\n /** Your own state to get back after the redirect (kept in storage, not sent). */\n returnTo?: string;\n}\n\nexport interface Session {\n accessToken: string;\n refreshToken: string | null;\n /** Absolute time (ms) the access token expires. */\n expiresAt: number;\n scope: Scope[];\n /** The member's pairwise subject for this association. */\n sub: string | null;\n /** `test` for sessions minted through a sandbox client. */\n mode?: 'live' | 'test';\n}\n\nexport interface RedirectResult {\n session: Session;\n /** The `returnTo` given to `signIn()`, if any. */\n returnTo: string | null;\n}\n\nexport interface SignOutOptions {\n /** Also end the member's Vimine session (single sign-out): leaves the page for the app's logout route. */\n everywhere?: boolean;\n /** Where the app sends the member afterwards (must be on a registered origin); default: `redirectUri`. */\n postLogoutRedirectUri?: string;\n state?: string;\n}\n\ninterface PendingFlow {\n verifier: string;\n state: string;\n redirectUri: string;\n scope: string;\n returnTo: string | null;\n createdAt: number;\n}\n\nconst decodeJwtPayload = (token: string): Record<string, unknown> | null => {\n try {\n const part = token.split('.')[1];\n if (!part) return null;\n const json = atob(part.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n};\n\nexport class Vimine {\n readonly options: Required<Pick<VimineOptions, 'clientId' | 'redirectUri' | 'apiUrl' | 'appUrl' | 'locale'>> & VimineOptions;\n /** The public, credential-less endpoints (verify a card, an association's profile, fiscal code, card keys). */\n readonly public: PublicApi;\n private readonly storage: TokenStorage;\n private readonly fetchImpl: typeof fetch;\n private readonly keys: { session: string; flow: string };\n private refreshing: Promise<Session> | null = null;\n private readonly listeners = new Set<(session: Session | null) => void>();\n\n constructor(options: VimineOptions) {\n if (!options?.clientId) throw new VimineError('invalid_options', 'clientId is required');\n if (!options.redirectUri) throw new VimineError('invalid_options', 'redirectUri is required');\n this.options = {\n ...options,\n apiUrl: (options.apiUrl || DEFAULT_API_URL).replace(/\\/+$/, ''),\n appUrl: (options.appUrl || DEFAULT_APP_URL).replace(/\\/+$/, ''),\n locale: options.locale || 'it'\n };\n this.storage = resolveStorage(options.storage);\n this.fetchImpl = options.fetch || globalThis.fetch.bind(globalThis);\n const prefix = options.storageKey || `vimine:${options.clientId}:`;\n this.keys = { session: `${prefix}session`, flow: `${prefix}flow` };\n this.public = publicApi({ apiUrl: this.options.apiUrl, fetch: this.fetchImpl });\n // Sign-out (or sign-in) in another tab, when tokens live in localStorage.\n const w = globalThis as unknown as { addEventListener?: (t: string, l: (e: StorageEvent) => void) => void };\n if (options.storage === 'local' && typeof w.addEventListener === 'function') {\n w.addEventListener('storage', (e) => {\n if (e.key === this.keys.session) this.emit(this.getSession());\n });\n }\n }\n\n // ---- sign-in -----------------------------------------------------------------------------------\n\n /** Build the authorization URL and remember the pending flow. Use `signIn()` unless you render the link yourself. */\n async createSignInUrl(opts: SignInOptions = {}): Promise<string> {\n const { verifier, challenge } = await createPkce();\n const state = createState();\n const scopes = opts.scopes || this.options.scopes || ['profile:read', 'membership:read'];\n const flow: PendingFlow = { verifier, state, redirectUri: this.options.redirectUri, scope: scopes.join(' '), returnTo: opts.returnTo ?? null, createdAt: Date.now() };\n this.storage.set(this.keys.flow, JSON.stringify(flow));\n const u = new URL(`${this.options.appUrl}/authorize`);\n u.searchParams.set('client_id', this.options.clientId);\n u.searchParams.set('redirect_uri', this.options.redirectUri);\n u.searchParams.set('response_type', 'code');\n u.searchParams.set('state', state);\n u.searchParams.set('code_challenge', challenge);\n u.searchParams.set('code_challenge_method', 'S256');\n u.searchParams.set('scope', flow.scope);\n u.searchParams.set('ui_locales', this.options.locale);\n if (opts.prompt) u.searchParams.set('prompt', opts.prompt);\n return u.toString();\n }\n\n /**\n * Start the sign-in: navigates the TOP window to the hosted sign-in + consent page. Call it from a user\n * gesture (a click). From inside a cross-origin or sandboxed frame the navigation is refused (`framed`):\n * the hosted page is never shown in a frame.\n */\n async signIn(opts: SignInOptions = {}): Promise<void> {\n const url = await this.createSignInUrl(opts);\n const nav = this.options.navigate || defaultNavigate;\n try {\n nav(url);\n } catch (err) {\n this.storage.remove(this.keys.flow);\n throw new VimineError('framed', 'Sign in with Vimine cannot start from this frame', { cause: err });\n }\n }\n\n /** Does this URL carry the parameters of a sign-in redirect (`code`+`state` or `error`)? */\n hasRedirectParams(url?: string): boolean {\n const params = paramsOf(url);\n return !!params && ((params.has('code') && params.has('state')) || params.has('error'));\n }\n\n /**\n * On the redirect page: exchange the authorization code for tokens and store the session. Returns null when\n * the URL carries no sign-in parameters. Throws `state_mismatch` / `no_flow` for a redirect this client did\n * not start, and the OAuth error (`access_denied`, …) when the member did not authorize.\n */\n async handleRedirect(opts: { url?: string; cleanUrl?: boolean } = {}): Promise<RedirectResult | null> {\n const params = paramsOf(opts.url);\n if (!params || !this.hasRedirectParams(opts.url)) return null;\n const raw = this.storage.get(this.keys.flow);\n const flow: PendingFlow | null = raw ? (JSON.parse(raw) as PendingFlow) : null;\n const finish = () => {\n this.storage.remove(this.keys.flow);\n if (opts.cleanUrl !== false) cleanRedirectParams();\n };\n if (params.has('error')) {\n finish();\n throw new VimineError(params.get('error') || 'access_denied', params.get('error_description') || 'The member did not authorize this app');\n }\n if (!flow) throw new VimineError('no_flow', 'No sign-in was started from this browser (storage empty or expired)');\n if (params.get('state') !== flow.state) throw new VimineError('state_mismatch', 'The redirect does not match the sign-in that was started');\n const tokens = await this.tokenRequest({\n grant_type: 'authorization_code',\n code: params.get('code') || '',\n code_verifier: flow.verifier,\n client_id: this.options.clientId,\n redirect_uri: flow.redirectUri\n });\n finish();\n const session = this.storeTokens(tokens);\n return { session, returnTo: flow.returnTo };\n }\n\n // ---- session -----------------------------------------------------------------------------------\n\n getSession(): Session | null {\n const raw = this.storage.get(this.keys.session);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as Session;\n } catch {\n return null;\n }\n }\n\n isSignedIn(): boolean {\n return !!this.getSession();\n }\n\n /** A valid access token, refreshed when about to expire. Throws `not_signed_in` when there is no session. */\n async getAccessToken(): Promise<string> {\n const session = this.getSession();\n if (!session) throw new VimineError('not_signed_in', 'No Vimine session: call signIn() first');\n if (session.expiresAt - Date.now() > REFRESH_LEAD_MS) return session.accessToken;\n return (await this.refresh()).accessToken;\n }\n\n /** Rotate the session (single-flight). An unusable refresh token ends the session. */\n refresh(): Promise<Session> {\n if (this.refreshing) return this.refreshing;\n this.refreshing = (async () => {\n const session = this.getSession();\n if (!session?.refreshToken) {\n this.clearSession();\n throw new VimineError('not_signed_in', 'No refresh token: sign in again');\n }\n try {\n const tokens = await this.tokenRequest({ grant_type: 'refresh_token', refresh_token: session.refreshToken, client_id: this.options.clientId });\n return this.storeTokens(tokens);\n } catch (err) {\n if (err instanceof VimineError && err.isAuthError) this.clearSession();\n throw err;\n } finally {\n this.refreshing = null;\n }\n })();\n return this.refreshing;\n }\n\n /** Revoke the session (RFC 7009) and forget it; with `everywhere`, also end the member's Vimine session. */\n async signOut(opts: SignOutOptions = {}): Promise<void> {\n const session = this.getSession();\n this.clearSession();\n if (session?.refreshToken) {\n await withNetworkError(\n this.fetchImpl(`${this.options.apiUrl}/v1/oauth/revoke`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({ token: session.refreshToken, token_type_hint: 'refresh_token' }).toString()\n })\n ).catch(() => {\n /* revocation is best effort: the tokens are already forgotten here */\n });\n }\n if (opts.everywhere) {\n const u = new URL(`${this.options.appUrl}/oauth/logout`);\n u.searchParams.set('client_id', this.options.clientId);\n u.searchParams.set('post_logout_redirect_uri', opts.postLogoutRedirectUri || this.options.redirectUri);\n if (opts.state) u.searchParams.set('state', opts.state);\n (this.options.navigate || defaultNavigate)(u.toString());\n }\n }\n\n /** Subscribe to session changes (sign-in, refresh, sign-out; other tabs when storage is `local`). */\n onChange(listener: (session: Session | null) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n // ---- API ---------------------------------------------------------------------------------------\n\n /** An authenticated call to the API; JSON in and out, problem details as `VimineError`, one retry after a refresh on 401. */\n async request<T>(path: string, init: RequestInit & { idempotencyKey?: string } = {}): Promise<T> {\n const attempt = async (token: string): Promise<Response> => {\n const headers: Record<string, string> = { Accept: 'application/json', Authorization: `Bearer ${token}` };\n if (init.body !== undefined) headers['Content-Type'] = 'application/json';\n if (init.idempotencyKey) headers['Idempotency-Key'] = init.idempotencyKey;\n const given = init.headers as Record<string, string> | undefined;\n const { idempotencyKey: _ignored, ...rest } = init;\n return this.fetchImpl(`${this.options.apiUrl}${path}`, { ...rest, headers: { ...headers, ...(given || {}) } });\n };\n let res = await withNetworkError(attempt(await this.getAccessToken()));\n if (res.status === 401) {\n const refreshed = await this.refresh();\n res = await withNetworkError(attempt(refreshed.accessToken));\n }\n return jsonOrThrow<T>(res);\n }\n\n /** The member's profile (`profile:read` / `profile:write`). */\n readonly me = {\n get: (): Promise<Me> => this.request<Me>('/v1/me'),\n /**\n * A fiscal code that disagrees with the particulars answers 422 with a `codicefiscale_mismatch` entry in\n * `errors[]`; when that entry says `confirmable: true` the person may confirm it: send `codicefiscale_confirmed: true`.\n */\n update: (patch: MeUpdate): Promise<Me> => this.request<Me>('/v1/me', { method: 'PATCH', body: JSON.stringify(patch) })\n };\n\n /** The member's membership in this association (`membership:read`, `membership:request`, `statuto:accept`). */\n readonly membership = {\n get: (): Promise<Membership> => this.request<Membership>('/v1/me/membership'),\n /**\n * Ask for a membership. 422 `identification_required` when the profile is not identified yet — a fiscal code, or\n * date, place and country of birth: `errors[]` names what is missing; complete it with `me.update()` and ask again.\n */\n request: (body: MembershipRequest, opts: { idempotencyKey?: string } = {}): Promise<MembershipRequestResult> =>\n this.request<MembershipRequestResult>('/v1/me/membership', { method: 'POST', body: JSON.stringify(body), idempotencyKey: opts.idempotencyKey || createState() }),\n events: (params: { limit?: number; cursor?: string } = {}): Promise<MembershipEvents> => {\n const q = new URLSearchParams();\n if (params.limit) q.set('limit', String(params.limit));\n if (params.cursor) q.set('cursor', params.cursor);\n const qs = q.toString();\n return this.request<MembershipEvents>(`/v1/me/membership/events${qs ? `?${qs}` : ''}`);\n },\n statuto: (): Promise<StatutoInfo> => this.request<StatutoInfo>('/v1/me/membership/statuto'),\n acceptStatuto: (body: StatutoAccept): Promise<{ accepted: true; version: number }> =>\n this.request('/v1/me/membership/statuto/accept', { method: 'POST', body: JSON.stringify(body) }),\n /** The signed card token and its window. 409 `not_active` unless the membership is active: only an active membership has a card. */\n card: (): Promise<Card> => this.request<Card>('/v1/me/membership/card'),\n /** Self-service renewal (`membership:request`): renewed at once for a free type with no approval gate, else a request. */\n renew: (body: StatutoAccept, opts: { idempotencyKey?: string } = {}): Promise<RenewResult> =>\n this.request<RenewResult>('/v1/me/membership/renew', { method: 'POST', body: JSON.stringify({ accept_statuto: body }), idempotencyKey: opts.idempotencyKey || createState() }),\n /** Network consent (`network:manage`); 409 `not_eligible` when the membership type is not in the network. */\n setNetworkOptIn: (optIn: boolean): Promise<NetworkOptIn> => this.request<NetworkOptIn>('/v1/me/membership/network-opt-in', { method: 'PATCH', body: JSON.stringify({ opt_in: optIn }) }),\n /** A Save-to-Google-Wallet link for the card (`membership:read`); 409 `not_active` when there is no card yet, 503 when the deployment has no wallet issuer. */\n googleWalletUrl: (): Promise<{ url: string }> => this.request<{ url: string }>('/v1/me/membership/wallet/google'),\n /** The card as SVG markup (with the current QR) — inline it, or hand it to `<vimine-card>`. 409 `not_active` unless the membership is active. */\n cardSvg: async (): Promise<string> => {\n const token = await this.getAccessToken();\n const res = await withNetworkError(this.fetchImpl(`${this.options.apiUrl}/v1/me/membership/card.svg`, { headers: { Accept: 'image/svg+xml', Authorization: `Bearer ${token}` } }));\n if (!res.ok) throw await VimineError.fromResponse(res);\n return res.text();\n },\n /** Ask the API to e-mail the member their card (SVG + QR attached). 409 `not_active` unless the membership is active. */\n emailCard: (): Promise<Accepted> => this.request<Accepted>('/v1/me/membership/card/email', { method: 'POST' })\n };\n\n /**\n * The member's legal acceptances (`legal:read`, `legal:accept`): what they accepted or acknowledged, what is still\n * pending — the account terms, the platform privacy notice, this association's notice to members — and the call\n * that records one at the in-force version your app showed (422 `<kind>_outdated` otherwise).\n */\n readonly legal = {\n acceptances: (params: { locale?: Locale } = {}): Promise<MyAcceptances> => this.request<MyAcceptances>(`/v1/me/acceptances${params.locale ? `?locale=${params.locale}` : ''}`),\n record: (body: AcceptanceInput, opts: { idempotencyKey?: string } = {}): Promise<AcceptanceResult> =>\n this.request<AcceptanceResult>('/v1/me/acceptances', { method: 'POST', body: JSON.stringify(body), idempotencyKey: opts.idempotencyKey || createState() })\n };\n\n /** Events of the association (`events:read`): published ones, members-only included — the public ones need no sign-in: `publicApi().events`. */\n readonly events = {\n /** `filter`: upcoming (default) | past | cancelled | all; `from` / `to` bound `starts_at`. */\n list: (params: EventListParams = {}): Promise<EventList> => this.request<EventList>(`/v1/events${eventQuery(params)}`),\n get: (slug: string, params: LocaleParam = {}): Promise<Event> => this.request<Event>(`/v1/events/${encodeURIComponent(slug)}${localeQuery(params)}`),\n /** May the member register, per registration type, with reasons. */\n eligibility: (slug: string): Promise<Eligibility> => this.request<Eligibility>(`/v1/events/${encodeURIComponent(slug)}/eligibility`)\n };\n\n /** The member's event registrations (`registrations:read` / `registrations:write`). */\n readonly registrations = {\n /**\n * Register for an event: a free type answers `confirmed` with the QR `token`; a paid one answers `reserved`\n * with `payment_instructions` until the association records the contribution. `422 not_eligible` carries\n * the reasons. Retries are safe: an `Idempotency-Key` is generated unless you pass one.\n */\n create: (slug: string, body: RegistrationRequest, opts: { idempotencyKey?: string } = {}): Promise<Registration> =>\n this.request<Registration>(`/v1/events/${encodeURIComponent(slug)}/registrations`, { method: 'POST', body: JSON.stringify(body), idempotencyKey: opts.idempotencyKey || createState() }),\n /** The member's registrations, newest event first (`filter: 'upcoming'` for the ones still to come). */\n list: (params: { filter?: 'upcoming' | 'all' } = {}): Promise<RegistrationList> => this.request<RegistrationList>(`/v1/me/registrations${params.filter ? `?filter=${params.filter}` : ''}`),\n get: (id: string): Promise<Registration> => this.request<Registration>(`/v1/me/registrations/${encodeURIComponent(id)}`),\n /** Cancel inside the event's cancellation window — `409 window_closed` otherwise. */\n cancel: (id: string): Promise<Registration> => this.request<Registration>(`/v1/me/registrations/${encodeURIComponent(id)}`, { method: 'DELETE' }),\n /** The QR payload of a confirmed registration (what the door scans), or null. */\n tokenPayload: async (id: string): Promise<string | null> => (await this.request<Registration>(`/v1/me/registrations/${encodeURIComponent(id)}`)).token || null\n };\n\n /** The apps the member authorized in this association. */\n readonly connections = {\n list: (): Promise<{ items: Connection[] }> => this.request('/v1/me/connections'),\n revoke: (clientId: string): Promise<void> => this.request<void>(`/v1/me/connections/${encodeURIComponent(clientId)}`, { method: 'DELETE' })\n };\n\n // ---- internals ---------------------------------------------------------------------------------\n\n private async tokenRequest(form: Record<string, string>): Promise<TokenResponse> {\n const res = await withNetworkError(\n this.fetchImpl(`${this.options.apiUrl}/v1/oauth/token`, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams(form).toString()\n })\n );\n return jsonOrThrow<TokenResponse>(res);\n }\n\n private storeTokens(tokens: TokenResponse): Session {\n const claims = decodeJwtPayload(tokens.access_token);\n const session: Session = {\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token ?? this.getSession()?.refreshToken ?? null,\n expiresAt: Date.now() + Math.max(0, tokens.expires_in) * 1000,\n scope: String(tokens.scope || '').split(/\\s+/).filter(Boolean) as Scope[],\n sub: tokens.sub ?? (typeof claims?.sub === 'string' ? claims.sub : null),\n mode: claims?.mode === 'test' ? 'test' : 'live'\n };\n this.storage.set(this.keys.session, JSON.stringify(session));\n this.emit(session);\n return session;\n }\n\n private clearSession(): void {\n const had = !!this.storage.get(this.keys.session);\n this.storage.remove(this.keys.session);\n if (had) this.emit(null);\n }\n\n private emit(session: Session | null): void {\n for (const l of this.listeners) {\n try {\n l(session);\n } catch {\n /* a listener must not break the others */\n }\n }\n }\n}\n\nconst paramsOf = (url?: string): URLSearchParams | null => {\n if (url) {\n try {\n return new URL(url, 'http://localhost').searchParams;\n } catch {\n return null;\n }\n }\n const loc = (globalThis as unknown as { location?: Location }).location;\n return loc ? new URLSearchParams(loc.search) : null;\n};\n\nconst cleanRedirectParams = (): void => {\n const g = globalThis as unknown as { history?: History; location?: Location };\n if (!g.history || !g.location) return;\n const u = new URL(g.location.href);\n for (const k of ['code', 'state', 'error', 'error_description']) u.searchParams.delete(k);\n try {\n g.history.replaceState(g.history.state, '', u.toString());\n } catch {\n /* ignore */\n }\n};\n\nconst defaultNavigate = (url: string): void => {\n const w = globalThis as unknown as { top?: Window; self?: Window; location?: Location };\n const top = w.top || w.self;\n if (!top) throw new Error('No window to navigate');\n // Navigating the top window from a cross-origin frame throws — which is the refusal we want.\n top.location.assign(url);\n};\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["// @vimine/sdk — Sign in with Vimine (OAuth 2.1 + PKCE) and the member API, for websites and apps of\n// associations on vimine.network. Zero dependencies; browser-first (WebCrypto, fetch), also fine in Node ≥ 18\n// with a storage of your choice.\n//\n// const mp = new Vimine({ clientId: 'vmc_…', redirectUri: 'https://www.example.org/callback' });\n// await mp.signIn(); // → the hosted sign-in + consent page, then back to redirectUri\n// await mp.handleRedirect(); // on the callback page: exchanges the code, stores the session\n// const membership = await mp.membership.get();\n//\n// The member's password is never typed into your page: sign-in happens on vimine.network, your site only ever\n// holds tokens for the permissions the member granted.\nimport { VimineError } from './errors.js';\nimport { createPkce, createState } from './pkce.js';\nimport { DEFAULT_API_URL, eventQuery, jsonOrThrow, localeQuery, publicApi, withNetworkError, type PublicApi } from './public.js';\nimport { resolveStorage, type StorageKind, type TokenStorage } from './storage.js';\nimport type {\n AcceptanceInput,\n AcceptanceResult,\n Accepted,\n AssociationRef,\n Card,\n Connection,\n Eligibility,\n Event,\n EventList,\n EventListParams,\n Locale,\n LocaleParam,\n Me,\n Membership,\n MembershipEvents,\n MembershipRequest,\n MembershipRequestResult,\n MeUpdate,\n MyAcceptances,\n NetworkOptIn,\n Registration,\n RegistrationList,\n RegistrationRequest,\n RenewResult,\n Scope,\n StatutoAccept,\n StatutoInfo,\n TokenResponse\n} from './types.js';\n\nexport { VimineError } from './errors.js';\nexport type { FieldError, ProblemDetails } from './errors.js';\nexport { createPkce, createState, createVerifier, createChallenge, base64url } from './pkce.js';\nexport { MemoryStorage, type StorageKind, type TokenStorage } from './storage.js';\n/** The OpenAPI document's own vocabulary (generated from openapi/v1.json — `npm run spec:types`). */\nexport type * as Spec from './generated.js';\nexport { publicApi, DEFAULT_API_URL, eventQuery, type PublicApi, type PublicOptions } from './public.js';\nexport type * from './types.js';\n\nexport const DEFAULT_APP_URL = 'https://app.vimine.network';\n/** Refresh this long before the access token expires. */\nconst REFRESH_LEAD_MS = 30_000;\n\nexport interface VimineOptions {\n /** Your client id (`vmc_…`), from the association's developer console. */\n clientId: string;\n /** One of the redirect URIs registered for the client — the page that calls `handleRedirect()`. */\n redirectUri: string;\n /** Default permissions to ask for; `signIn()` may override. */\n scopes?: Scope[];\n /** The API origin (default production). */\n apiUrl?: string;\n /** The app origin that hosts sign-in and consent (default production). */\n appUrl?: string;\n /** Where tokens live: `session` (default, per tab), `local` (shared across tabs), `memory`, or your own adapter. */\n storage?: StorageKind | TokenStorage;\n /** Storage key prefix (default derived from the client id). */\n storageKey?: string;\n /** UI language of the hosted pages (a platform language; Chinese by script: `zh-Hans`, `zh-Hant`). */\n locale?: Locale;\n /** Custom fetch (tests, polyfills). */\n fetch?: typeof fetch;\n /** How to leave the page (default: the top window's `location.assign`). */\n navigate?: (url: string) => void;\n}\n\nexport interface SignInOptions {\n scopes?: Scope[];\n /** `login` forces the credential form even with a live session; `consent` forces the consent screen. */\n prompt?: 'login' | 'consent';\n /** Your own state to get back after the redirect (kept in storage, not sent). */\n returnTo?: string;\n}\n\nexport interface Session {\n accessToken: string;\n refreshToken: string | null;\n /** Absolute time (ms) the access token expires. */\n expiresAt: number;\n scope: Scope[];\n /** The member's pairwise subject for this association. */\n sub: string | null;\n /** `test` for sessions minted through a sandbox client. */\n mode?: 'live' | 'test';\n /** The association the member signed in to (name and picture, to show beside them); null from an API that predates it. */\n aps?: AssociationRef | null;\n}\n\nexport interface RedirectResult {\n session: Session;\n /** The `returnTo` given to `signIn()`, if any. */\n returnTo: string | null;\n}\n\nexport interface SignOutOptions {\n /** Also end the member's Vimine session (single sign-out): leaves the page for the app's logout route. */\n everywhere?: boolean;\n /** Where the app sends the member afterwards (must be on a registered origin); default: `redirectUri`. */\n postLogoutRedirectUri?: string;\n state?: string;\n}\n\ninterface PendingFlow {\n verifier: string;\n state: string;\n redirectUri: string;\n scope: string;\n returnTo: string | null;\n createdAt: number;\n}\n\nconst decodeJwtPayload = (token: string): Record<string, unknown> | null => {\n try {\n const part = token.split('.')[1];\n if (!part) return null;\n const json = atob(part.replace(/-/g, '+').replace(/_/g, '/'));\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return null;\n }\n};\n\nexport class Vimine {\n readonly options: Required<Pick<VimineOptions, 'clientId' | 'redirectUri' | 'apiUrl' | 'appUrl' | 'locale'>> & VimineOptions;\n /** The public, credential-less endpoints (verify a card, an association's profile, fiscal code, card keys). */\n readonly public: PublicApi;\n private readonly storage: TokenStorage;\n private readonly fetchImpl: typeof fetch;\n private readonly keys: { session: string; flow: string };\n private refreshing: Promise<Session> | null = null;\n private readonly listeners = new Set<(session: Session | null) => void>();\n\n constructor(options: VimineOptions) {\n if (!options?.clientId) throw new VimineError('invalid_options', 'clientId is required');\n if (!options.redirectUri) throw new VimineError('invalid_options', 'redirectUri is required');\n this.options = {\n ...options,\n apiUrl: (options.apiUrl || DEFAULT_API_URL).replace(/\\/+$/, ''),\n appUrl: (options.appUrl || DEFAULT_APP_URL).replace(/\\/+$/, ''),\n locale: options.locale || 'it'\n };\n this.storage = resolveStorage(options.storage);\n this.fetchImpl = options.fetch || globalThis.fetch.bind(globalThis);\n const prefix = options.storageKey || `vimine:${options.clientId}:`;\n this.keys = { session: `${prefix}session`, flow: `${prefix}flow` };\n this.public = publicApi({ apiUrl: this.options.apiUrl, fetch: this.fetchImpl });\n // Sign-out (or sign-in) in another tab, when tokens live in localStorage.\n const w = globalThis as unknown as { addEventListener?: (t: string, l: (e: StorageEvent) => void) => void };\n if (options.storage === 'local' && typeof w.addEventListener === 'function') {\n w.addEventListener('storage', (e) => {\n if (e.key === this.keys.session) this.emit(this.getSession());\n });\n }\n }\n\n // ---- sign-in -----------------------------------------------------------------------------------\n\n /** Build the authorization URL and remember the pending flow. Use `signIn()` unless you render the link yourself. */\n async createSignInUrl(opts: SignInOptions = {}): Promise<string> {\n const { verifier, challenge } = await createPkce();\n const state = createState();\n const scopes = opts.scopes || this.options.scopes || ['profile:read', 'membership:read'];\n const flow: PendingFlow = { verifier, state, redirectUri: this.options.redirectUri, scope: scopes.join(' '), returnTo: opts.returnTo ?? null, createdAt: Date.now() };\n this.storage.set(this.keys.flow, JSON.stringify(flow));\n const u = new URL(`${this.options.appUrl}/authorize`);\n u.searchParams.set('client_id', this.options.clientId);\n u.searchParams.set('redirect_uri', this.options.redirectUri);\n u.searchParams.set('response_type', 'code');\n u.searchParams.set('state', state);\n u.searchParams.set('code_challenge', challenge);\n u.searchParams.set('code_challenge_method', 'S256');\n u.searchParams.set('scope', flow.scope);\n u.searchParams.set('ui_locales', this.options.locale);\n if (opts.prompt) u.searchParams.set('prompt', opts.prompt);\n return u.toString();\n }\n\n /**\n * Start the sign-in: navigates the TOP window to the hosted sign-in + consent page. Call it from a user\n * gesture (a click). From inside a cross-origin or sandboxed frame the navigation is refused (`framed`):\n * the hosted page is never shown in a frame.\n */\n async signIn(opts: SignInOptions = {}): Promise<void> {\n const url = await this.createSignInUrl(opts);\n const nav = this.options.navigate || defaultNavigate;\n try {\n nav(url);\n } catch (err) {\n this.storage.remove(this.keys.flow);\n throw new VimineError('framed', 'Sign in with Vimine cannot start from this frame', { cause: err });\n }\n }\n\n /** Does this URL carry the parameters of a sign-in redirect (`code`+`state` or `error`)? */\n hasRedirectParams(url?: string): boolean {\n const params = paramsOf(url);\n return !!params && ((params.has('code') && params.has('state')) || params.has('error'));\n }\n\n /**\n * On the redirect page: exchange the authorization code for tokens and store the session. Returns null when\n * the URL carries no sign-in parameters. Throws `state_mismatch` / `no_flow` for a redirect this client did\n * not start, and the OAuth error (`access_denied`, …) when the member did not authorize.\n */\n async handleRedirect(opts: { url?: string; cleanUrl?: boolean } = {}): Promise<RedirectResult | null> {\n const params = paramsOf(opts.url);\n if (!params || !this.hasRedirectParams(opts.url)) return null;\n const raw = this.storage.get(this.keys.flow);\n const flow: PendingFlow | null = raw ? (JSON.parse(raw) as PendingFlow) : null;\n const finish = () => {\n this.storage.remove(this.keys.flow);\n if (opts.cleanUrl !== false) cleanRedirectParams();\n };\n if (params.has('error')) {\n finish();\n throw new VimineError(params.get('error') || 'access_denied', params.get('error_description') || 'The member did not authorize this app');\n }\n if (!flow) throw new VimineError('no_flow', 'No sign-in was started from this browser (storage empty or expired)');\n if (params.get('state') !== flow.state) throw new VimineError('state_mismatch', 'The redirect does not match the sign-in that was started');\n const tokens = await this.tokenRequest({\n grant_type: 'authorization_code',\n code: params.get('code') || '',\n code_verifier: flow.verifier,\n client_id: this.options.clientId,\n redirect_uri: flow.redirectUri\n });\n finish();\n const session = this.storeTokens(tokens);\n return { session, returnTo: flow.returnTo };\n }\n\n // ---- session -----------------------------------------------------------------------------------\n\n getSession(): Session | null {\n const raw = this.storage.get(this.keys.session);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as Session;\n } catch {\n return null;\n }\n }\n\n isSignedIn(): boolean {\n return !!this.getSession();\n }\n\n /** A valid access token, refreshed when about to expire. Throws `not_signed_in` when there is no session. */\n async getAccessToken(): Promise<string> {\n const session = this.getSession();\n if (!session) throw new VimineError('not_signed_in', 'No Vimine session: call signIn() first');\n if (session.expiresAt - Date.now() > REFRESH_LEAD_MS) return session.accessToken;\n return (await this.refresh()).accessToken;\n }\n\n /** Rotate the session (single-flight). An unusable refresh token ends the session. */\n refresh(): Promise<Session> {\n if (this.refreshing) return this.refreshing;\n this.refreshing = (async () => {\n const session = this.getSession();\n if (!session?.refreshToken) {\n this.clearSession();\n throw new VimineError('not_signed_in', 'No refresh token: sign in again');\n }\n try {\n const tokens = await this.tokenRequest({ grant_type: 'refresh_token', refresh_token: session.refreshToken, client_id: this.options.clientId });\n return this.storeTokens(tokens);\n } catch (err) {\n if (err instanceof VimineError && err.isAuthError) this.clearSession();\n throw err;\n } finally {\n this.refreshing = null;\n }\n })();\n return this.refreshing;\n }\n\n /** Revoke the session (RFC 7009) and forget it; with `everywhere`, also end the member's Vimine session. */\n async signOut(opts: SignOutOptions = {}): Promise<void> {\n const session = this.getSession();\n this.clearSession();\n if (session?.refreshToken) {\n await withNetworkError(\n this.fetchImpl(`${this.options.apiUrl}/v1/oauth/revoke`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({ token: session.refreshToken, token_type_hint: 'refresh_token' }).toString()\n })\n ).catch(() => {\n /* revocation is best effort: the tokens are already forgotten here */\n });\n }\n if (opts.everywhere) {\n const u = new URL(`${this.options.appUrl}/oauth/logout`);\n u.searchParams.set('client_id', this.options.clientId);\n u.searchParams.set('post_logout_redirect_uri', opts.postLogoutRedirectUri || this.options.redirectUri);\n if (opts.state) u.searchParams.set('state', opts.state);\n (this.options.navigate || defaultNavigate)(u.toString());\n }\n }\n\n /** Subscribe to session changes (sign-in, refresh, sign-out; other tabs when storage is `local`). */\n onChange(listener: (session: Session | null) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n // ---- API ---------------------------------------------------------------------------------------\n\n /** An authenticated call to the API; JSON in and out, problem details as `VimineError`, one retry after a refresh on 401. */\n async request<T>(path: string, init: RequestInit & { idempotencyKey?: string } = {}): Promise<T> {\n const attempt = async (token: string): Promise<Response> => {\n const headers: Record<string, string> = { Accept: 'application/json', Authorization: `Bearer ${token}` };\n if (init.body !== undefined) headers['Content-Type'] = 'application/json';\n if (init.idempotencyKey) headers['Idempotency-Key'] = init.idempotencyKey;\n const given = init.headers as Record<string, string> | undefined;\n const { idempotencyKey: _ignored, ...rest } = init;\n return this.fetchImpl(`${this.options.apiUrl}${path}`, { ...rest, headers: { ...headers, ...(given || {}) } });\n };\n let res = await withNetworkError(attempt(await this.getAccessToken()));\n if (res.status === 401) {\n const refreshed = await this.refresh();\n res = await withNetworkError(attempt(refreshed.accessToken));\n }\n return jsonOrThrow<T>(res);\n }\n\n /** The member's profile (`profile:read` / `profile:write`). */\n readonly me = {\n get: (): Promise<Me> => this.request<Me>('/v1/me'),\n /**\n * A fiscal code that disagrees with the particulars answers 422 with a `codicefiscale_mismatch` entry in\n * `errors[]`; when that entry says `confirmable: true` the person may confirm it: send `codicefiscale_confirmed: true`.\n */\n update: (patch: MeUpdate): Promise<Me> => this.request<Me>('/v1/me', { method: 'PATCH', body: JSON.stringify(patch) })\n };\n\n /** The member's membership in this association (`membership:read`, `membership:request`, `statuto:accept`). */\n readonly membership = {\n get: (): Promise<Membership> => this.request<Membership>('/v1/me/membership'),\n /**\n * Ask for a membership. 422 `identification_required` when the profile is not identified yet — a fiscal code, or\n * date, place and country of birth: `errors[]` names what is missing; complete it with `me.update()` and ask again.\n */\n request: (body: MembershipRequest, opts: { idempotencyKey?: string } = {}): Promise<MembershipRequestResult> =>\n this.request<MembershipRequestResult>('/v1/me/membership', { method: 'POST', body: JSON.stringify(body), idempotencyKey: opts.idempotencyKey || createState() }),\n events: (params: { limit?: number; cursor?: string } = {}): Promise<MembershipEvents> => {\n const q = new URLSearchParams();\n if (params.limit) q.set('limit', String(params.limit));\n if (params.cursor) q.set('cursor', params.cursor);\n const qs = q.toString();\n return this.request<MembershipEvents>(`/v1/me/membership/events${qs ? `?${qs}` : ''}`);\n },\n statuto: (): Promise<StatutoInfo> => this.request<StatutoInfo>('/v1/me/membership/statuto'),\n acceptStatuto: (body: StatutoAccept): Promise<{ accepted: true; version: number }> =>\n this.request('/v1/me/membership/statuto/accept', { method: 'POST', body: JSON.stringify(body) }),\n /** The signed card token and its window. 409 `not_active` unless the membership is active: only an active membership has a card. */\n card: (): Promise<Card> => this.request<Card>('/v1/me/membership/card'),\n /** Self-service renewal (`membership:request`): renewed at once for a free type with no approval gate, else a request. */\n renew: (body: StatutoAccept, opts: { idempotencyKey?: string } = {}): Promise<RenewResult> =>\n this.request<RenewResult>('/v1/me/membership/renew', { method: 'POST', body: JSON.stringify({ accept_statuto: body }), idempotencyKey: opts.idempotencyKey || createState() }),\n /** Network consent (`network:manage`); 409 `not_eligible` when the membership type is not in the network. */\n setNetworkOptIn: (optIn: boolean): Promise<NetworkOptIn> => this.request<NetworkOptIn>('/v1/me/membership/network-opt-in', { method: 'PATCH', body: JSON.stringify({ opt_in: optIn }) }),\n /** A Save-to-Google-Wallet link for the card (`membership:read`); 409 `not_active` when there is no card yet, 503 when the deployment has no wallet issuer. */\n googleWalletUrl: (): Promise<{ url: string }> => this.request<{ url: string }>('/v1/me/membership/wallet/google'),\n /** The card as SVG markup (with the current QR) — inline it, or hand it to `<vimine-card>`. 409 `not_active` unless the membership is active. */\n cardSvg: async (): Promise<string> => {\n const token = await this.getAccessToken();\n const res = await withNetworkError(this.fetchImpl(`${this.options.apiUrl}/v1/me/membership/card.svg`, { headers: { Accept: 'image/svg+xml', Authorization: `Bearer ${token}` } }));\n if (!res.ok) throw await VimineError.fromResponse(res);\n return res.text();\n },\n /** Ask the API to e-mail the member their card (SVG + QR attached). 409 `not_active` unless the membership is active. */\n emailCard: (): Promise<Accepted> => this.request<Accepted>('/v1/me/membership/card/email', { method: 'POST' })\n };\n\n /**\n * The member's legal acceptances (`legal:read`, `legal:accept`): what they accepted or acknowledged, what is still\n * pending — the account terms, the platform privacy notice, this association's notice to members — and the call\n * that records one at the in-force version your app showed (422 `<kind>_outdated` otherwise).\n */\n readonly legal = {\n acceptances: (params: { locale?: Locale } = {}): Promise<MyAcceptances> => this.request<MyAcceptances>(`/v1/me/acceptances${params.locale ? `?locale=${params.locale}` : ''}`),\n record: (body: AcceptanceInput, opts: { idempotencyKey?: string } = {}): Promise<AcceptanceResult> =>\n this.request<AcceptanceResult>('/v1/me/acceptances', { method: 'POST', body: JSON.stringify(body), idempotencyKey: opts.idempotencyKey || createState() })\n };\n\n /** Events of the association (`events:read`): published ones, members-only included — the public ones need no sign-in: `publicApi().events`. */\n readonly events = {\n /** `filter`: upcoming (default) | past | cancelled | all; `from` / `to` bound `starts_at`. */\n list: (params: EventListParams = {}): Promise<EventList> => this.request<EventList>(`/v1/events${eventQuery(params)}`),\n get: (slug: string, params: LocaleParam = {}): Promise<Event> => this.request<Event>(`/v1/events/${encodeURIComponent(slug)}${localeQuery(params)}`),\n /** May the member register, per registration type, with reasons. */\n eligibility: (slug: string): Promise<Eligibility> => this.request<Eligibility>(`/v1/events/${encodeURIComponent(slug)}/eligibility`)\n };\n\n /** The member's event registrations (`registrations:read` / `registrations:write`). */\n readonly registrations = {\n /**\n * Register for an event: a free type answers `confirmed` with the QR `token`; a paid one answers `reserved`\n * with `payment_instructions` until the association records the contribution. `422 not_eligible` carries\n * the reasons. Retries are safe: an `Idempotency-Key` is generated unless you pass one.\n */\n create: (slug: string, body: RegistrationRequest, opts: { idempotencyKey?: string } = {}): Promise<Registration> =>\n this.request<Registration>(`/v1/events/${encodeURIComponent(slug)}/registrations`, { method: 'POST', body: JSON.stringify(body), idempotencyKey: opts.idempotencyKey || createState() }),\n /** The member's registrations, newest event first (`filter: 'upcoming'` for the ones still to come). */\n list: (params: { filter?: 'upcoming' | 'all' } = {}): Promise<RegistrationList> => this.request<RegistrationList>(`/v1/me/registrations${params.filter ? `?filter=${params.filter}` : ''}`),\n get: (id: string): Promise<Registration> => this.request<Registration>(`/v1/me/registrations/${encodeURIComponent(id)}`),\n /** Cancel inside the event's cancellation window — `409 window_closed` otherwise. */\n cancel: (id: string): Promise<Registration> => this.request<Registration>(`/v1/me/registrations/${encodeURIComponent(id)}`, { method: 'DELETE' }),\n /** The QR payload of a confirmed registration (what the door scans), or null. */\n tokenPayload: async (id: string): Promise<string | null> => (await this.request<Registration>(`/v1/me/registrations/${encodeURIComponent(id)}`)).token || null\n };\n\n /** The apps the member authorized in this association. */\n readonly connections = {\n list: (): Promise<{ items: Connection[] }> => this.request('/v1/me/connections'),\n revoke: (clientId: string): Promise<void> => this.request<void>(`/v1/me/connections/${encodeURIComponent(clientId)}`, { method: 'DELETE' })\n };\n\n // ---- internals ---------------------------------------------------------------------------------\n\n private async tokenRequest(form: Record<string, string>): Promise<TokenResponse> {\n const res = await withNetworkError(\n this.fetchImpl(`${this.options.apiUrl}/v1/oauth/token`, {\n method: 'POST',\n headers: { Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams(form).toString()\n })\n );\n return jsonOrThrow<TokenResponse>(res);\n }\n\n private storeTokens(tokens: TokenResponse): Session {\n const claims = decodeJwtPayload(tokens.access_token);\n const session: Session = {\n accessToken: tokens.access_token,\n refreshToken: tokens.refresh_token ?? this.getSession()?.refreshToken ?? null,\n expiresAt: Date.now() + Math.max(0, tokens.expires_in) * 1000,\n scope: String(tokens.scope || '').split(/\\s+/).filter(Boolean) as Scope[],\n sub: tokens.sub ?? (typeof claims?.sub === 'string' ? claims.sub : null),\n mode: claims?.mode === 'test' ? 'test' : 'live',\n aps: tokens.aps ?? this.getSession()?.aps ?? null\n };\n this.storage.set(this.keys.session, JSON.stringify(session));\n this.emit(session);\n return session;\n }\n\n private clearSession(): void {\n const had = !!this.storage.get(this.keys.session);\n this.storage.remove(this.keys.session);\n if (had) this.emit(null);\n }\n\n private emit(session: Session | null): void {\n for (const l of this.listeners) {\n try {\n l(session);\n } catch {\n /* a listener must not break the others */\n }\n }\n }\n}\n\nconst paramsOf = (url?: string): URLSearchParams | null => {\n if (url) {\n try {\n return new URL(url, 'http://localhost').searchParams;\n } catch {\n return null;\n }\n }\n const loc = (globalThis as unknown as { location?: Location }).location;\n return loc ? new URLSearchParams(loc.search) : null;\n};\n\nconst cleanRedirectParams = (): void => {\n const g = globalThis as unknown as { history?: History; location?: Location };\n if (!g.history || !g.location) return;\n const u = new URL(g.location.href);\n for (const k of ['code', 'state', 'error', 'error_description']) u.searchParams.delete(k);\n try {\n g.history.replaceState(g.history.state, '', u.toString());\n } catch {\n /* ignore */\n }\n};\n\nconst defaultNavigate = (url: string): void => {\n const w = globalThis as unknown as { top?: Window; self?: Window; location?: Location };\n const top = w.top || w.self;\n if (!top) throw new Error('No window to navigate');\n // Navigating the top window from a cross-origin frame throws — which is the refusal we want.\n top.location.assign(url);\n};\n"]}
package/dist/types.d.ts CHANGED
@@ -13,16 +13,20 @@ export interface TokenResponse {
13
13
  scope: string;
14
14
  /** Pairwise subject of the member (per association); absent on client tokens. */
15
15
  sub?: string;
16
+ /** The association the member signed in to, to show beside them; absent on client tokens. */
17
+ aps?: AssociationRef;
18
+ }
19
+ /** An association as the sign-in page names it: its slug, its name and its picture (public, or `null`). */
20
+ export interface AssociationRef {
21
+ slug: string;
22
+ name: string;
23
+ picture_url: string | null;
16
24
  }
17
25
  export interface ClientInfo {
18
26
  client_id: string;
19
27
  name: string;
20
28
  kind: 'public' | 'native' | 'confidential' | 'first_party';
21
- aps: {
22
- slug: string;
23
- name: string;
24
- picture_url: string | null;
25
- };
29
+ aps: AssociationRef;
26
30
  scopes: Array<{
27
31
  code: Scope;
28
32
  label: string;
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,kGAAkG","sourcesContent":["// Wire types of the Vimine API v1 — hand-kept in sync with openapi/v1.json (the document is the source of\n// truth; a generated file may replace this one later). Field names are the JSON names, unchanged.\n\n/** Permissions a member (user scopes) or an association's own system (client scopes) may hold. */\nexport type Scope =\n | 'profile:read'\n | 'profile:write'\n | 'membership:read'\n | 'membership:request'\n | 'statuto:accept'\n | 'network:manage'\n | 'identity:signup'\n | 'enroll:write'\n | 'verify:read'\n | 'memberships:read'\n | 'checkins:write'\n | 'webhooks:manage'\n | 'events:read'\n | 'registrations:read'\n | 'registrations:write';\n\n/** `rejected`: the request for admission was not accepted (a different act from `revoked`, which excludes a member). */\nexport type MembershipStatus = 'pending' | 'active' | 'suspended' | 'revoked' | 'rejected';\n/** What the card is worth right now: `valid`, `expired`, `statuto_required` (re-acceptance overdue) or `inactive`. */\n/** `not_yet_valid`: active and unexpired, but inside the association's usability delay — see `Membership.valid_from`. */\nexport type MembershipVerdict = 'valid' | 'expired' | 'not_yet_valid' | 'statuto_required' | 'inactive';\n\n// ---- OAuth ------------------------------------------------------------------------------------------\n\nexport interface TokenResponse {\n access_token: string;\n token_type: 'Bearer';\n expires_in: number;\n refresh_token?: string;\n scope: string;\n /** Pairwise subject of the member (per association); absent on client tokens. */\n sub?: string;\n}\n\nexport interface ClientInfo {\n client_id: string;\n name: string;\n kind: 'public' | 'native' | 'confidential' | 'first_party';\n aps: { slug: string; name: string; picture_url: string | null };\n scopes: Array<{ code: Scope; label: string }>;\n}\n\n// ---- member surface (/v1/me*) -------------------------------------------------------------------------\n\n/**\n * A language the platform speaks (`it`, `en` today). Wherever the API takes one it also takes a regional tag\n * (`en-GB`) and reduces it; a language it does not speak is ignored, never an error — except on `PATCH /v1/me`.\n */\n// The platform's languages. A request in one the platform does not serve yet (a language still in review) gets the\n// platform's default, and the answer's `locale` says so.\nexport type Locale = 'it' | 'en' | 'zh-Hans' | 'zh-Hant' | 'fr' | 'es' | 'de' | 'pt-BR';\n\n/** Ask for the association's copy in a language (`?locale=`). Default: the member's own, then `Accept-Language`, then the association's. */\nexport interface LocaleParam {\n locale?: Locale | string;\n}\n\nexport interface Me {\n sub: string;\n email: string;\n email_verified: boolean;\n first_name: string | null;\n last_name: string | null;\n phone: string | null;\n /** ISO date (YYYY-MM-DD) */\n dob: string | null;\n /** Demographic only: it is never cross-checked against a fiscal code. */\n gender: 'M' | 'F' | null;\n /** Comune (born in Italy) or city, free text (born abroad). */\n birthplace: string | null;\n /** Country of birth, ISO 3166-1 alpha-2. */\n birth_country: string | null;\n /** Optional: a person may have none. */\n codicefiscale: string | null;\n /** How the person is identified; `null` = not identified yet (they cannot request a membership). */\n codicefiscale_check: CodiceFiscaleCheck | null;\n /** The language the person chose for the platform and its mails; `null` = never chosen (the request's, then the association's, applies). */\n locale: Locale | null;\n updated_at: string | null;\n}\n\n/**\n * How a person is identified — by a fiscal code OR by their particulars (date, place and country of birth), never\n * neither. `matched`: a fiscal code that agrees with the particulars; `mismatch_confirmed`: a code that disagrees,\n * confirmed by the person as the one on their health card; `absent`: no code, the particulars identify them.\n */\nexport type CodiceFiscaleCheck = 'matched' | 'mismatch_confirmed' | 'absent';\n\nexport interface MeUpdate {\n phone?: string | null;\n dob?: string | null;\n gender?: 'M' | 'F' | null;\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2. For a person born abroad a fiscal code encodes only the STATE: this is what it is compared with. */\n birth_country?: string | null;\n /** May be added later, or set to `null`. Validated and cross-checked when present (422 `codicefiscale_mismatch`). */\n codicefiscale?: string | null;\n /** Write-only: the person confirms a code that disagrees with their particulars (only after a `confirmable: true`). */\n codicefiscale_confirmed?: boolean;\n /** The person's language; `null` clears the choice. 422 `unsupported` for a language the platform does not speak. */\n locale?: Locale | null;\n}\n\nexport interface MembershipTypeRef {\n uid: string;\n cod: string;\n name: string;\n}\n\nexport interface MembershipStatuto {\n current_version: number | null;\n current_sha256: string | null;\n accepted_version_id: string | null;\n accepted_at: string | null;\n /** A newer statuto was published since the member accepted one. */\n pending: boolean;\n /** … and the association's grace window for re-acceptance has elapsed. */\n overdue: boolean;\n}\n\nexport interface CardToken {\n /** The `vmt_…` token: what a QR carries and what `/v1/verify/{card_token}` checks. */\n token: string;\n /** Validity window (unix seconds). */\n nbf: number;\n exp: number;\n}\n\nexport interface Membership {\n id: string;\n status: MembershipStatus;\n verdict: MembershipVerdict;\n subdate: string | null;\n issued_at: string | null;\n expires_at: string | null;\n membership_type: MembershipTypeRef | null;\n statuto: MembershipStatuto;\n /**\n * Why a `pending` membership is still pending, IN ORDER: the association's approval of the request first (when it\n * admits by decision of its board), then the quota of a paid type. Empty when active.\n */\n pending_reasons: PendingReason[];\n /** May the quota be paid yet? `false` while the approval is still pending: approval opens payment. */\n payment_open: boolean;\n /** When the card starts to count at the door (the association's usability delay); `null` = since activation. */\n valid_from: string | null;\n /** Is the card usable right now? `status` may be `active` while this is still `false` (see `valid_from`). */\n usable: boolean;\n /** The quota of a paid membership type and whether it is paid for the current period; `null` for a free type. */\n quota: { amount: number; currency: string; paid: boolean } | null;\n /** The association's instructions for paying the quota, only once the payment is open (`payment_open`). */\n payment_instructions: string | null;\n /** Days to expiry (negative once expired). */\n expires_in_days: number | null;\n /** Self-service renewal: open 60 days before expiry; `requested_at` once the member asked. */\n renewal: { window_open: boolean; requested_at: string | null };\n network_opt_in: boolean;\n /** The signed card token. `null` unless `status` is `active` (a pending, suspended or revoked membership has no card) or when card signing is not configured. */\n card: CardToken | null;\n}\n\nexport type PendingReason = 'approval' | 'payment';\n/** How an association admits its members (`GET /v1/aps/{slug}` → `aps.admission.model`). */\nexport type AdmissionModel = 'board' | 'provisional' | 'automatic';\n\nexport interface MembershipRequest {\n /** Membership type uid; optional when the association offers exactly one. */\n membership_type?: string;\n /** Must name the in-force statuto (see `Statuto.version`; `sha256` when published). */\n accept_statuto: { version: number; sha256?: string };\n /**\n * The association's privacy notice the person read on your page (`ApsPublicConfig.privacy_notice`; add `locale` when\n * you showed a translation). REQUIRED while a notice is in force that the person has not acknowledged yet\n * (`legal.acceptances()` → `pending.privacy_notice`): 422 `validation_failed` on `privacy_notice` without it, 422\n * `privacy_notice_outdated` when it is not the in-force version. Ignored once they stand at the in-force one.\n */\n privacy_notice?: { version: number; sha256?: string; locale?: Locale | string };\n /**\n * Residence or, where different, domicile — kept on the association's own record of the member. REQUIRED where the\n * association declared `member_address: required` (422 `validation_failed` on `address`), stored where it declared\n * `optional`, ignored where it collects none.\n */\n address?: MemberAddress;\n /** The language of the page the person used (`it`, `en`): which translation of the notice they read. */\n locale?: Locale | string;\n}\n\n/** A free type with no approval gate is issued `active` at once; otherwise `pending` with its reasons. */\n/** What every answer about a membership request says about its gates. */\nexport interface MembershipGates {\n /** In order: the association's approval first (board model), then the fee. Empty when active. */\n pending_reasons: PendingReason[];\n /** May the fee be paid yet? `false` while the approval is pending: approval opens payment. */\n payment_open: boolean;\n /** When the card becomes usable, for an active membership inside the usability delay; `null` otherwise. */\n valid_from: string | null;\n}\nexport type MembershipRequestResult =\n | ({ created: true; status: MembershipStatus; id: string } & MembershipGates)\n | ({ already_requested: true; status: MembershipStatus } & MembershipGates);\n\nexport interface MembershipEvent {\n from: MembershipStatus | null;\n to: MembershipStatus;\n reason: string | null;\n changed_at: string;\n channel: string;\n}\n\nexport interface MembershipEvents {\n items: MembershipEvent[];\n next_cursor: string | null;\n}\n\nexport interface StatutoInfo {\n uid: string;\n version: number;\n approvaldate: string | null;\n sha256: string | null;\n content: string | null;\n document_url: string | null;\n accepted: boolean;\n accepted_at: string | null;\n overdue: boolean;\n}\n\nexport interface StatutoAccept {\n version: number;\n sha256?: string;\n}\n\nexport interface Card extends CardToken {\n status: MembershipStatus;\n}\n\nexport interface Connection {\n client_id: string;\n name: string;\n kind: ClientInfo['kind'];\n scopes: Scope[];\n granted_at: string;\n}\n\n// ---- public surface -------------------------------------------------------------------------------------\n\nexport interface Verification {\n status: 'active' | 'inactive';\n valid_until?: string;\n /** With `reason: 'not_yet_valid'`: the card is genuine and active, and becomes usable at this moment. */\n valid_from?: string;\n reason?: 'expired' | 'invalid' | 'not_yet_valid';\n}\n\nexport interface MembershipType {\n uid: string;\n cod: string;\n name: string;\n description: string | null;\n quota_amount: number | null;\n currency: string;\n expiry_model: 'solar_year' | 'rolling_12' | 'rolling_24' | 'prorated_solar' | 'custom';\n network_eligible: boolean;\n}\n\nexport interface Statuto {\n uid: string;\n version: number;\n approvaldate: string | null;\n sha256: string | null;\n content: string | null;\n document_url: string | null;\n}\n\nexport interface AssociationPublicConfig {\n /** The language this answer is written in: the one you asked for when the association offers it, its own otherwise. */\n locale: Locale;\n /** The languages the association offers: its own, plus those it enabled. */\n locales: Locale[];\n aps: {\n slug: string;\n name: string;\n picture_url: string | null;\n citta: string | null;\n provincia: string | null;\n enroll_enabled: boolean;\n /** Enrolment is on AND the association can take one more member right now (plan caps are never disclosed). */\n accepting_requests: boolean;\n /**\n * The private beta: the association takes only the people it invited — `accepting_requests` is then false and\n * enrolment answers 403 `not_available`; invitees join from the link they receive by mail.\n */\n invitation_only: boolean;\n /**\n * How the association admits its members — tell an applicant up front. `board`: the request waits for a decision\n * of the association's board, and any fee is paid after it; `provisional`: admitted at once, ratified later;\n * `automatic`: active as soon as the conditions are met. `delay_hours`: hours between admission and a USABLE card\n * (0 = at once) — the membership is active from admission, the card counts at the door only afterwards.\n */\n admission: { model: AdmissionModel; delay_hours: number };\n /** @deprecated Kept for compatibility: `true` when `admission.model` is `board`. Read `admission`. */\n approval_required: boolean;\n /**\n * Whether the association collects its members' address — of every member or of nobody. `none`: do not ask (an\n * `address` sent anyway is not stored); `optional`; `required`: enrolment answers 422 `required` on `address`\n * without one.\n */\n member_address: MemberAddressPolicy;\n /** How to pay the quota (IBAN, causale…), when the association published it. */\n payment_instructions: string | null;\n /**\n * The activities of general interest the association carries out (Italian Third Sector Code, art. 5): `cod` is\n * the letter of the article, `description` its Italian wording; one is marked as prevalent.\n */\n activity_sectors: Array<{ cod: string; description: string; prevalent: boolean }>;\n /**\n * Present when the association is registered in the RUNTS (the Italian national register of Third Sector\n * entities), as checked by the platform against the official public lists; `null` otherwise. Never typed by\n * the association.\n */\n registry: {\n section: 'APS' | 'ODV' | 'EF' | 'IS' | 'RA' | 'SOMS' | 'ALTRI' | null;\n /** Repertory number. */\n number: string | null;\n registered_on: string | null;\n /** Date of the official list the check ran against. */\n checked_on: string | null;\n } | null;\n };\n membership_types: MembershipType[];\n statuto: Statuto | null;\n}\n\nexport interface FiscalCodeCheck {\n /** Codice fiscale (16 characters). */\n code: string;\n first_name?: string;\n last_name?: string;\n gender?: 'M' | 'F';\n /** Date of birth, YYYY-MM-DD. */\n date?: string;\n /** Birthplace: the comune, for a person born in Italy. */\n place?: string;\n /**\n * Birth country, ISO 3166-1 alpha-2. A code encodes the comune for people born in Italy and only the STATE for\n * everybody else: anything but `IT` is compared with that state, and `place` is ignored.\n */\n country?: string;\n}\n\n/** What may disagree with a fiscal code. `gender` only where it is sent: enrolment and the profile never cross-check it. */\nexport type FiscalCodeMismatch = 'lastName' | 'firstName' | 'gender' | 'date' | 'place';\n/** `names_swapped`: the code matches once surname and given name are exchanged. */\nexport type FiscalCodeHint = 'names_swapped';\n\nexport interface FiscalCodeResult {\n valid: boolean;\n /** `invalid`: structure or check character; `mismatch`: a well-formed code that disagrees with the data sent. */\n error: 'invalid' | 'mismatch' | null;\n /** What disagrees with the code, when `error` is `mismatch`. */\n mismatches: FiscalCodeMismatch[];\n hints: FiscalCodeHint[];\n /** The date of birth the code itself encodes (YYYY-MM-DD). */\n birth_date: string | null;\n /** The birth country the code itself encodes, ISO 3166-1 alpha-2 (`IT` for a comune). */\n birth_country: string | null;\n}\n\nexport interface CardKeys {\n keys: Array<{ kty: string; crv: string; x: string; kid: string; use: string; alg: string }>;\n}\n\n// ---- client (server-side) surface ---------------------------------------------------------------------\n\n// ---- server-side signup + enrolment (client scopes identity:signup / enroll:write) ---------------------\n\n/** A person your system registers on Vimine (`POST /v1/signup`). */\nexport interface SignupInput {\n email: string;\n first_name: string;\n last_name: string;\n phone?: string | null;\n /** YYYY-MM-DD */\n dob?: string | null;\n /** Demographic only: it is not cross-checked. */\n gender?: 'M' | 'F' | null;\n /** Comune (born in Italy) or city, free text (born abroad). */\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2. Send it for a person born abroad: their fiscal code encodes only the state. */\n birth_country?: string | null;\n /** Validated and cross-checked against the other fields when present. */\n codicefiscale?: string | null;\n /** The person confirms a code that disagrees with their particulars (422 `codicefiscale_mismatch` with `confirmable: true`). */\n codicefiscale_confirmed?: boolean;\n /** The account terms (`platform_terms`) the person accepted on your site — optional; when given it must name the in-force version (`GET /v1/legal/platform_terms`). */\n accept_terms?: LegalRef;\n /** The platform privacy notice (`platform_privacy`) the person read on your site — optional, same rule. */\n acknowledge_privacy?: LegalRef;\n /**\n * The language of the page the person filled in. It decides the language of the mails that follow and becomes the\n * preference of a NEW account; an existing account keeps its own.\n */\n locale?: Locale | string;\n}\n\n/** Whether an association collects its members' address (`GET /v1/aps/{slug}` → `aps.member_address`). */\nexport type MemberAddressPolicy = 'none' | 'optional' | 'required';\n\n/** A member's address, as `POST /v1/enroll`, `POST /v1/me/membership` and `POST /v1/enroll/confirm` take it. */\nexport interface MemberAddress {\n /** `residence` (the default) or, where different, `domicile`. */\n kind?: 'residence' | 'domicile';\n /** Street and number. */\n line: string;\n postal_code?: string | null;\n city: string;\n /** Italian addresses only (two letters); dropped abroad. */\n province?: string | null;\n /** ISO 3166-1 alpha-2 (default `IT`). */\n country?: string;\n}\n\n/**\n * `POST /v1/enroll/confirm` after a 409 `identification_required`: what the account still lacks — a fiscal code, or\n * date, place and country of birth. It completes the EMPTY fields of the profile, never over what is there.\n */\nexport interface EnrollIdentification {\n /** YYYY-MM-DD */\n dob?: string;\n birthplace?: string;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string;\n codicefiscale?: string;\n codicefiscale_confirmed?: boolean;\n}\n\n/** A published legal text named by version (and hash when published). */\nexport interface LegalRef {\n version: string;\n sha256?: string;\n}\n\n/** A membership request your system submits for a person (`POST /v1/enroll`). */\nexport interface EnrollInput extends SignupInput {\n /**\n * Optional. A person is identified by a fiscal code OR by `dob` + `birthplace` + `birth_country` — never neither\n * (422 `required` on each missing particular). When present it is validated and cross-checked against the names,\n * the date and the place (the state, for people born abroad).\n */\n codicefiscale?: string | null;\n /**\n * Residence or, where different, domicile. Asked of every member or of nobody: the public profile says what the\n * association declared (`aps.member_address`).\n */\n address?: MemberAddress;\n /** Membership type uid; optional when the association offers exactly one. */\n membership_type?: string;\n /** The in-force statuto the person accepted on your site (see `Statuto.version`; `sha256` when published). */\n accept_statuto: { version: number; sha256?: string };\n /**\n * The association's privacy notice the person read on your site (`ApsPublicConfig.privacy_notice`). REQUIRED when the\n * association publishes one; 422 `privacy_notice_outdated` when it is not the in-force version.\n */\n privacy_notice?: { version: number; sha256?: string; locale?: Locale | string };\n}\n\n/** One acceptance, acknowledgement or consent the person recorded (`GET /v1/me/acceptances`). */\nexport interface AcceptanceRecord {\n at: string;\n action: 'accepted' | 'acknowledged' | 'consented' | 'withdrawn' | 'declared';\n channel: 'ui' | 'public' | 'api' | 'job' | 'paper';\n kind: string;\n title: string;\n version: string;\n sha256: string | null;\n /** Hash of the text actually shown. */\n rendered_sha256: string | null;\n locale: string | null;\n /** The association the act concerns, when any. */\n association: string | null;\n}\n\n/** A document the person has not acted on at its in-force version. */\nexport interface PendingDocument {\n kind: string;\n title: string;\n locale: string;\n version: string | number;\n sha256: string | null;\n effective_from: string | null;\n /** What the person is asked to do. */\n action: 'accepted' | 'acknowledged' | 'consented';\n /** Never acted on any version of this kind (false: a new version requires it again). */\n first: boolean;\n}\n\nexport interface MyAcceptances {\n items: AcceptanceRecord[];\n pending: {\n /** Account-layer documents still to accept / acknowledge. */\n platform: PendingDocument[];\n /** This association's notice to members, when not yet acknowledged. */\n privacy_notice: PendingDocument | null;\n };\n}\n\n/** `POST /v1/me/acceptances`: the in-force version your app showed. */\nexport interface AcceptanceInput {\n /** `platform_terms` | `platform_privacy` | `network_consent` | `privacy_notice` */\n kind: string;\n version: string | number;\n sha256?: string;\n}\n\nexport interface AcceptanceResult {\n recorded: true;\n kind: string;\n action: string;\n version: string;\n at: string;\n}\n\n/** The uniform answer of the creating routes: whatever happened behind the address, it was accepted. */\nexport interface Accepted {\n status: 'accepted';\n}\n\n/** `POST /v1/enroll/confirm` — the outcome of the confirmation link an existing account's owner uses. */\nexport interface EnrollConfirmResult {\n status: MembershipStatus;\n /** The person already had a membership request or membership here; nothing new was created. */\n already: boolean;\n /** In order: the association's approval first (board model), then the fee. */\n pending_reasons: PendingReason[];\n payment_open: boolean;\n valid_from: string | null;\n association: { name: string; slug: string };\n /**\n * Only for a link sent by the association's hosted enrolment page when that page was opened from one of its public\n * events: what became of the place asked for together with the request. `null` for every other link.\n */\n event?: EnrolledPlace | null;\n}\n\n/** The place asked for with a membership request made from an event's page (`EnrollConfirmResult.event`). */\nexport interface EnrolledPlace {\n slug: string;\n title: string;\n starts_at: string;\n timezone: string;\n place: string | null;\n registration_type: { uid: string; name: string; amount: number; currency: string };\n /**\n * `confirmed`: the place is theirs. `reserved`: held, see `waiting`. `held`: the membership request itself still\n * waits for the address to be confirmed, and no place was asked for. `unavailable`: no place, see `reasons`.\n */\n state: 'confirmed' | 'reserved' | 'held' | 'unavailable';\n /** What a `reserved` place waits for: the membership to become active, the contribution, or both. */\n waiting: ('membership' | 'contribution')[];\n /** Why the place is `unavailable`: the reasons of the eligibility endpoint. */\n reasons: string[];\n reserved_until: string | null;\n /** How to pay a contribution that is owed, in the association's words. */\n payment_instructions: string | null;\n /** The person held this place before the link was used. */\n already: boolean;\n}\n\n/** `POST /v1/me/membership/renew` — renewed at once (free type, no approval gate) or turned into a request. */\nexport interface RenewResult {\n renewed: boolean;\n requested: boolean;\n status: MembershipStatus;\n expires_at: string | null;\n renewal_requested_at: string | null;\n}\n\n/** `PATCH /v1/me/membership/network-opt-in` */\nexport interface NetworkOptIn {\n network_opt_in: boolean;\n network_opt_in_at: string | null;\n}\n\n/** `POST /v1/checkins` — a door check-in from a scanned card token. No personal data. */\n/** `POST /v1/checkins` for a CARD token. */\nexport interface CardCheckinResult {\n kind: 'card';\n verdict: MembershipVerdict;\n status: MembershipStatus;\n membership_id: string;\n valid_until: string | null;\n /** With `verdict: 'not_yet_valid'`: when the card becomes usable. The scan is recorded all the same. */\n valid_from: string | null;\n /**\n * A note for whoever staffs the gate, never part of `verdict`: it restricts nothing. `pending`: the member has no\n * verifiable fiscal code and nobody of the association has looked at a document yet — show it. Cleared from the\n * association's console. `null`: nothing to check. The public `verifyCard` never carries it.\n */\n identity_check: IdentityCheck | null;\n checked_in_at: string;\n}\n/**\n * The identity check at first presence (`CardCheckinResult.identity_check`). `pending`: a document is still to be\n * looked at; `verified`: somebody of the association looked at one; `flagged`: somebody did, and it did not agree —\n * a matter for the association's office, which revokes nothing by itself.\n */\nexport type IdentityCheck = 'pending' | 'verified' | 'flagged';\nexport type RegistrationCheckinVerdict = 'valid' | 'already_checked_in' | 'not_confirmed' | 'cancelled' | 'event_cancelled' | 'membership_invalid';\n/** `POST /v1/checkins` for an event REGISTRATION token (`k:'reg'` in the payload). */\nexport interface RegistrationCheckinResult {\n kind: 'registration';\n verdict: RegistrationCheckinVerdict;\n status: RegistrationStatus;\n registration_id: string;\n event: { slug: string; title: string; starts_at: string };\n registration_type: string | null;\n membership_id: string | null;\n membership_verdict: MembershipVerdict | null;\n /** True the first time this registration is checked in. */\n first: boolean;\n checked_in_at: string | null;\n}\nexport type CheckinResult = CardCheckinResult | RegistrationCheckinResult;\n\n/** One row of `GET /v1/memberships` — ids and status only. */\nexport interface MembershipListItem {\n id: string;\n status: MembershipStatus;\n verdict: MembershipVerdict;\n membership_type: { cod: string } | null;\n issued_at: string | null;\n valid_until: string | null;\n updated_at: string;\n}\nexport interface MembershipList {\n items: MembershipListItem[];\n next_cursor: string | null;\n}\nexport interface MembershipListParams {\n status?: MembershipStatus;\n /** RFC 3339: only rows changed after this instant (incremental sync). */\n updated_since?: string;\n limit?: number;\n cursor?: string;\n}\n\nexport interface MembershipStatusInfo {\n id: string;\n status: MembershipStatus;\n verdict: MembershipVerdict;\n valid_until: string | null;\n membership_type: { cod: string } | null;\n}\n\nexport interface SandboxMember {\n email: string;\n name: string;\n status: MembershipStatus;\n expires_at: string | null;\n statuto_accepted: boolean;\n}\n\nexport interface SandboxMembers {\n slug: string;\n members: SandboxMember[];\n}\n\nexport interface SandboxReset {\n /** The synthetic members' shared password — shown only here. */\n password: string;\n members: Array<Pick<SandboxMember, 'email' | 'name' | 'status'>>;\n}\n\n// ---- events & registrations (/v1/aps/{slug}/events, /v1/events*, /v1/me/registrations*) ---------------------\n// Vocabulary: registration (iscrizione) and contribution (contributo) — never \"ticket\".\n\nexport type EventStatus = 'published' | 'completed' | 'cancelled';\nexport type EventVisibility = 'members_only' | 'public';\nexport type RegistrationStatus = 'reserved' | 'confirmed' | 'cancelled' | 'refunded';\n/** Why a registration was cancelled. */\nexport type RegistrationCancelReason =\n /** The member cancelled it, inside the event's cancellation window. */\n | 'user'\n /** The association's secretariat cancelled it. */\n | 'staff'\n /** A reserved place whose contribution did not arrive before the hold ran out. */\n | 'expired'\n | 'event_cancelled'\n /** A place held while the membership request was pending, for an event that starts before the new card is usable. */\n | 'card_not_valid_yet'\n /** The association did not accept the membership request (or the provisional admission) the place was held under. */\n | 'membership_rejected'\n /** The association revoked the membership the place needed. */\n | 'membership_revoked';\n/** Why a registration type is not open right now. */\nexport type RegistrationTypeReason = 'sold_out' | 'registration_not_open' | 'registration_closed';\n/** Why the member may not register (`GET /v1/events/{slug}/eligibility`, `422 not_eligible`). */\nexport type EligibilityReason =\n | 'membership_required'\n | 'membership_not_active'\n /** The event starts before the member's card is usable (the association's usability delay). */\n | 'membership_not_yet_valid'\n | 'membership_type_not_allowed'\n | 'sold_out'\n | 'event_full'\n | 'registration_not_open'\n | 'registration_closed'\n | 'max_per_user'\n | 'event_past'\n | 'event_cancelled'\n | 'event_not_published'\n | 'plan_limit'\n | 'invalid_type';\n\nexport interface EventLocation {\n name: string | null;\n address: string | null;\n lat: number | null;\n lng: number | null;\n}\n\n/** An admission class of an event: free (`amount` 0) or a contribution; places and window are live. */\nexport interface RegistrationType {\n uid: string;\n cod: string;\n name: string;\n description: string | null;\n amount: number;\n currency: string;\n quantity: number | null;\n /** Places left (never who holds them); null = unlimited. */\n remaining: number | null;\n max_per_user: number;\n requires_active_membership: boolean;\n open: boolean;\n reason: RegistrationTypeReason | null;\n opens_at: string | null;\n closes_at: string | null;\n}\n\n/** An event as the API describes it: headless copy, dates, place, images, live availability per type. */\nexport interface Event {\n id: string;\n slug: string;\n /**\n * The language the `title` was served in. When it is not the one you asked for, the association wrote no\n * translation: you got its own text — never a machine translation. Each text falls back on its own.\n */\n locale: Locale;\n /** The languages in which this event has a title. */\n locales: Locale[];\n title: string;\n summary: string | null;\n /** Markdown — render it yourself. */\n description_md: string | null;\n starts_at: string;\n ends_at: string | null;\n timezone: string;\n status: EventStatus;\n visibility: EventVisibility;\n location: EventLocation | null;\n cover_url: string | null;\n gallery: { url: string; alt: string | null; order: number }[];\n links: { label: string; url: string }[];\n registration: { opens_at: string | null; closes_at: string | null; capacity: number | null; remaining: number | null; cancellation_hours: number };\n registration_types: RegistrationType[];\n published_at: string | null;\n cancelled_at: string | null;\n cancel_reason: string | null;\n}\nexport interface EventList {\n items: Event[];\n}\nexport interface EventListParams extends LocaleParam {\n /** `upcoming` (default) | `past` | `cancelled` | `all` */\n filter?: 'upcoming' | 'past' | 'cancelled' | 'all';\n /** RFC 3339 bounds on `starts_at`. */\n from?: string;\n to?: string;\n limit?: number;\n}\n\nexport interface Eligibility {\n can_register: boolean;\n membership_verdict: MembershipVerdict | null;\n types: { uid: string; cod: string; can_register: boolean; reasons: EligibilityReason[]; pending_membership: boolean }[];\n}\n\nexport interface RegistrationRequest {\n registration_type: string;\n note?: string | null;\n quantity?: number;\n /** The language the registration was made in: the fallback for a member who never chose one. */\n locale?: Locale | string;\n}\n\n/** A person's registration (the member's own, or a guest's after the confirmation link). */\nexport interface Registration {\n id: string;\n status: RegistrationStatus;\n event: { id: string; slug: string; title: string; starts_at: string; ends_at: string | null; timezone: string; status: EventStatus; location: string | null; cancel_reason: string | null } | null;\n registration_type: { uid: string; cod: string; name: string; amount: number; currency: string } | null;\n quantity: number;\n reserved_until: string | null;\n checked_in_at: string | null;\n cancelled_at: string | null;\n cancel_reason: RegistrationCancelReason | null;\n can_cancel: boolean;\n payment: { status: 'recorded' | 'refunded' | 'void'; amount: number; currency: string; method: string; paid_at: string } | null;\n /** How to pay the contribution while `reserved` (the association's own text). */\n payment_instructions?: string | null;\n note: string | null;\n created_at: string;\n /** The registration QR payload (`vmt_…`), confirmed registrations only — draw it as a QR code. */\n token?: string | null;\n}\nexport interface RegistrationList {\n items: Registration[];\n}\n\n/** `POST /v1/events/{slug}/registrations/guest` (client scope `registrations:write`, public events only). */\nexport interface GuestRegistrationRequest {\n email: string;\n first_name: string;\n last_name: string;\n registration_type: string;\n note?: string | null;\n /** The language the registration was made in — for a guest, the language of every mail they receive. */\n locale?: Locale | string;\n}\n\n/** One row of `GET /v1/events/{slug}/registrations` — no personal data. */\nexport interface RegistrationListItem {\n id: string;\n status: RegistrationStatus;\n registration_type: string | null;\n membership_id: string | null;\n quantity: number;\n checked_in_at: string | null;\n created_at: string;\n}\nexport interface EventRegistrationList {\n items: RegistrationListItem[];\n next_cursor: string | null;\n}\nexport interface EventRegistrationListParams {\n status?: RegistrationStatus;\n limit?: number;\n cursor?: string;\n}\n\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,kGAAkG","sourcesContent":["// Wire types of the Vimine API v1 — hand-kept in sync with openapi/v1.json (the document is the source of\n// truth; a generated file may replace this one later). Field names are the JSON names, unchanged.\n\n/** Permissions a member (user scopes) or an association's own system (client scopes) may hold. */\nexport type Scope =\n | 'profile:read'\n | 'profile:write'\n | 'membership:read'\n | 'membership:request'\n | 'statuto:accept'\n | 'network:manage'\n | 'identity:signup'\n | 'enroll:write'\n | 'verify:read'\n | 'memberships:read'\n | 'checkins:write'\n | 'webhooks:manage'\n | 'events:read'\n | 'registrations:read'\n | 'registrations:write';\n\n/** `rejected`: the request for admission was not accepted (a different act from `revoked`, which excludes a member). */\nexport type MembershipStatus = 'pending' | 'active' | 'suspended' | 'revoked' | 'rejected';\n/** What the card is worth right now: `valid`, `expired`, `statuto_required` (re-acceptance overdue) or `inactive`. */\n/** `not_yet_valid`: active and unexpired, but inside the association's usability delay — see `Membership.valid_from`. */\nexport type MembershipVerdict = 'valid' | 'expired' | 'not_yet_valid' | 'statuto_required' | 'inactive';\n\n// ---- OAuth ------------------------------------------------------------------------------------------\n\nexport interface TokenResponse {\n access_token: string;\n token_type: 'Bearer';\n expires_in: number;\n refresh_token?: string;\n scope: string;\n /** Pairwise subject of the member (per association); absent on client tokens. */\n sub?: string;\n /** The association the member signed in to, to show beside them; absent on client tokens. */\n aps?: AssociationRef;\n}\n\n/** An association as the sign-in page names it: its slug, its name and its picture (public, or `null`). */\nexport interface AssociationRef {\n slug: string;\n name: string;\n picture_url: string | null;\n}\n\nexport interface ClientInfo {\n client_id: string;\n name: string;\n kind: 'public' | 'native' | 'confidential' | 'first_party';\n aps: AssociationRef;\n scopes: Array<{ code: Scope; label: string }>;\n}\n\n// ---- member surface (/v1/me*) -------------------------------------------------------------------------\n\n/**\n * A language the platform speaks (`it`, `en` today). Wherever the API takes one it also takes a regional tag\n * (`en-GB`) and reduces it; a language it does not speak is ignored, never an error — except on `PATCH /v1/me`.\n */\n// The platform's languages. A request in one the platform does not serve yet (a language still in review) gets the\n// platform's default, and the answer's `locale` says so.\nexport type Locale = 'it' | 'en' | 'zh-Hans' | 'zh-Hant' | 'fr' | 'es' | 'de' | 'pt-BR';\n\n/** Ask for the association's copy in a language (`?locale=`). Default: the member's own, then `Accept-Language`, then the association's. */\nexport interface LocaleParam {\n locale?: Locale | string;\n}\n\nexport interface Me {\n sub: string;\n email: string;\n email_verified: boolean;\n first_name: string | null;\n last_name: string | null;\n phone: string | null;\n /** ISO date (YYYY-MM-DD) */\n dob: string | null;\n /** Demographic only: it is never cross-checked against a fiscal code. */\n gender: 'M' | 'F' | null;\n /** Comune (born in Italy) or city, free text (born abroad). */\n birthplace: string | null;\n /** Country of birth, ISO 3166-1 alpha-2. */\n birth_country: string | null;\n /** Optional: a person may have none. */\n codicefiscale: string | null;\n /** How the person is identified; `null` = not identified yet (they cannot request a membership). */\n codicefiscale_check: CodiceFiscaleCheck | null;\n /** The language the person chose for the platform and its mails; `null` = never chosen (the request's, then the association's, applies). */\n locale: Locale | null;\n updated_at: string | null;\n}\n\n/**\n * How a person is identified — by a fiscal code OR by their particulars (date, place and country of birth), never\n * neither. `matched`: a fiscal code that agrees with the particulars; `mismatch_confirmed`: a code that disagrees,\n * confirmed by the person as the one on their health card; `absent`: no code, the particulars identify them.\n */\nexport type CodiceFiscaleCheck = 'matched' | 'mismatch_confirmed' | 'absent';\n\nexport interface MeUpdate {\n phone?: string | null;\n dob?: string | null;\n gender?: 'M' | 'F' | null;\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2. For a person born abroad a fiscal code encodes only the STATE: this is what it is compared with. */\n birth_country?: string | null;\n /** May be added later, or set to `null`. Validated and cross-checked when present (422 `codicefiscale_mismatch`). */\n codicefiscale?: string | null;\n /** Write-only: the person confirms a code that disagrees with their particulars (only after a `confirmable: true`). */\n codicefiscale_confirmed?: boolean;\n /** The person's language; `null` clears the choice. 422 `unsupported` for a language the platform does not speak. */\n locale?: Locale | null;\n}\n\nexport interface MembershipTypeRef {\n uid: string;\n cod: string;\n name: string;\n}\n\nexport interface MembershipStatuto {\n current_version: number | null;\n current_sha256: string | null;\n accepted_version_id: string | null;\n accepted_at: string | null;\n /** A newer statuto was published since the member accepted one. */\n pending: boolean;\n /** … and the association's grace window for re-acceptance has elapsed. */\n overdue: boolean;\n}\n\nexport interface CardToken {\n /** The `vmt_…` token: what a QR carries and what `/v1/verify/{card_token}` checks. */\n token: string;\n /** Validity window (unix seconds). */\n nbf: number;\n exp: number;\n}\n\nexport interface Membership {\n id: string;\n status: MembershipStatus;\n verdict: MembershipVerdict;\n subdate: string | null;\n issued_at: string | null;\n expires_at: string | null;\n membership_type: MembershipTypeRef | null;\n statuto: MembershipStatuto;\n /**\n * Why a `pending` membership is still pending, IN ORDER: the association's approval of the request first (when it\n * admits by decision of its board), then the quota of a paid type. Empty when active.\n */\n pending_reasons: PendingReason[];\n /** May the quota be paid yet? `false` while the approval is still pending: approval opens payment. */\n payment_open: boolean;\n /** When the card starts to count at the door (the association's usability delay); `null` = since activation. */\n valid_from: string | null;\n /** Is the card usable right now? `status` may be `active` while this is still `false` (see `valid_from`). */\n usable: boolean;\n /** The quota of a paid membership type and whether it is paid for the current period; `null` for a free type. */\n quota: { amount: number; currency: string; paid: boolean } | null;\n /** The association's instructions for paying the quota, only once the payment is open (`payment_open`). */\n payment_instructions: string | null;\n /** Days to expiry (negative once expired). */\n expires_in_days: number | null;\n /** Self-service renewal: open 60 days before expiry; `requested_at` once the member asked. */\n renewal: { window_open: boolean; requested_at: string | null };\n network_opt_in: boolean;\n /** The signed card token. `null` unless `status` is `active` (a pending, suspended or revoked membership has no card) or when card signing is not configured. */\n card: CardToken | null;\n}\n\nexport type PendingReason = 'approval' | 'payment';\n/** How an association admits its members (`GET /v1/aps/{slug}` → `aps.admission.model`). */\nexport type AdmissionModel = 'board' | 'provisional' | 'automatic';\n\nexport interface MembershipRequest {\n /** Membership type uid; optional when the association offers exactly one. */\n membership_type?: string;\n /** Must name the in-force statuto (see `Statuto.version`; `sha256` when published). */\n accept_statuto: { version: number; sha256?: string };\n /**\n * The association's privacy notice the person read on your page (`ApsPublicConfig.privacy_notice`; add `locale` when\n * you showed a translation). REQUIRED while a notice is in force that the person has not acknowledged yet\n * (`legal.acceptances()` → `pending.privacy_notice`): 422 `validation_failed` on `privacy_notice` without it, 422\n * `privacy_notice_outdated` when it is not the in-force version. Ignored once they stand at the in-force one.\n */\n privacy_notice?: { version: number; sha256?: string; locale?: Locale | string };\n /**\n * Residence or, where different, domicile — kept on the association's own record of the member. REQUIRED where the\n * association declared `member_address: required` (422 `validation_failed` on `address`), stored where it declared\n * `optional`, ignored where it collects none.\n */\n address?: MemberAddress;\n /** The language of the page the person used (`it`, `en`): which translation of the notice they read. */\n locale?: Locale | string;\n}\n\n/** A free type with no approval gate is issued `active` at once; otherwise `pending` with its reasons. */\n/** What every answer about a membership request says about its gates. */\nexport interface MembershipGates {\n /** In order: the association's approval first (board model), then the fee. Empty when active. */\n pending_reasons: PendingReason[];\n /** May the fee be paid yet? `false` while the approval is pending: approval opens payment. */\n payment_open: boolean;\n /** When the card becomes usable, for an active membership inside the usability delay; `null` otherwise. */\n valid_from: string | null;\n}\nexport type MembershipRequestResult =\n | ({ created: true; status: MembershipStatus; id: string } & MembershipGates)\n | ({ already_requested: true; status: MembershipStatus } & MembershipGates);\n\nexport interface MembershipEvent {\n from: MembershipStatus | null;\n to: MembershipStatus;\n reason: string | null;\n changed_at: string;\n channel: string;\n}\n\nexport interface MembershipEvents {\n items: MembershipEvent[];\n next_cursor: string | null;\n}\n\nexport interface StatutoInfo {\n uid: string;\n version: number;\n approvaldate: string | null;\n sha256: string | null;\n content: string | null;\n document_url: string | null;\n accepted: boolean;\n accepted_at: string | null;\n overdue: boolean;\n}\n\nexport interface StatutoAccept {\n version: number;\n sha256?: string;\n}\n\nexport interface Card extends CardToken {\n status: MembershipStatus;\n}\n\nexport interface Connection {\n client_id: string;\n name: string;\n kind: ClientInfo['kind'];\n scopes: Scope[];\n granted_at: string;\n}\n\n// ---- public surface -------------------------------------------------------------------------------------\n\nexport interface Verification {\n status: 'active' | 'inactive';\n valid_until?: string;\n /** With `reason: 'not_yet_valid'`: the card is genuine and active, and becomes usable at this moment. */\n valid_from?: string;\n reason?: 'expired' | 'invalid' | 'not_yet_valid';\n}\n\nexport interface MembershipType {\n uid: string;\n cod: string;\n name: string;\n description: string | null;\n quota_amount: number | null;\n currency: string;\n expiry_model: 'solar_year' | 'rolling_12' | 'rolling_24' | 'prorated_solar' | 'custom';\n network_eligible: boolean;\n}\n\nexport interface Statuto {\n uid: string;\n version: number;\n approvaldate: string | null;\n sha256: string | null;\n content: string | null;\n document_url: string | null;\n}\n\nexport interface AssociationPublicConfig {\n /** The language this answer is written in: the one you asked for when the association offers it, its own otherwise. */\n locale: Locale;\n /** The languages the association offers: its own, plus those it enabled. */\n locales: Locale[];\n aps: {\n slug: string;\n name: string;\n picture_url: string | null;\n citta: string | null;\n provincia: string | null;\n enroll_enabled: boolean;\n /** Enrolment is on AND the association can take one more member right now (plan caps are never disclosed). */\n accepting_requests: boolean;\n /**\n * The private beta: the association takes only the people it invited — `accepting_requests` is then false and\n * enrolment answers 403 `not_available`; invitees join from the link they receive by mail.\n */\n invitation_only: boolean;\n /**\n * How the association admits its members — tell an applicant up front. `board`: the request waits for a decision\n * of the association's board, and any fee is paid after it; `provisional`: admitted at once, ratified later;\n * `automatic`: active as soon as the conditions are met. `delay_hours`: hours between admission and a USABLE card\n * (0 = at once) — the membership is active from admission, the card counts at the door only afterwards.\n */\n admission: { model: AdmissionModel; delay_hours: number };\n /** @deprecated Kept for compatibility: `true` when `admission.model` is `board`. Read `admission`. */\n approval_required: boolean;\n /**\n * Whether the association collects its members' address — of every member or of nobody. `none`: do not ask (an\n * `address` sent anyway is not stored); `optional`; `required`: enrolment answers 422 `required` on `address`\n * without one.\n */\n member_address: MemberAddressPolicy;\n /** How to pay the quota (IBAN, causale…), when the association published it. */\n payment_instructions: string | null;\n /**\n * The activities of general interest the association carries out (Italian Third Sector Code, art. 5): `cod` is\n * the letter of the article, `description` its Italian wording; one is marked as prevalent.\n */\n activity_sectors: Array<{ cod: string; description: string; prevalent: boolean }>;\n /**\n * Present when the association is registered in the RUNTS (the Italian national register of Third Sector\n * entities), as checked by the platform against the official public lists; `null` otherwise. Never typed by\n * the association.\n */\n registry: {\n section: 'APS' | 'ODV' | 'EF' | 'IS' | 'RA' | 'SOMS' | 'ALTRI' | null;\n /** Repertory number. */\n number: string | null;\n registered_on: string | null;\n /** Date of the official list the check ran against. */\n checked_on: string | null;\n } | null;\n };\n membership_types: MembershipType[];\n statuto: Statuto | null;\n}\n\nexport interface FiscalCodeCheck {\n /** Codice fiscale (16 characters). */\n code: string;\n first_name?: string;\n last_name?: string;\n gender?: 'M' | 'F';\n /** Date of birth, YYYY-MM-DD. */\n date?: string;\n /** Birthplace: the comune, for a person born in Italy. */\n place?: string;\n /**\n * Birth country, ISO 3166-1 alpha-2. A code encodes the comune for people born in Italy and only the STATE for\n * everybody else: anything but `IT` is compared with that state, and `place` is ignored.\n */\n country?: string;\n}\n\n/** What may disagree with a fiscal code. `gender` only where it is sent: enrolment and the profile never cross-check it. */\nexport type FiscalCodeMismatch = 'lastName' | 'firstName' | 'gender' | 'date' | 'place';\n/** `names_swapped`: the code matches once surname and given name are exchanged. */\nexport type FiscalCodeHint = 'names_swapped';\n\nexport interface FiscalCodeResult {\n valid: boolean;\n /** `invalid`: structure or check character; `mismatch`: a well-formed code that disagrees with the data sent. */\n error: 'invalid' | 'mismatch' | null;\n /** What disagrees with the code, when `error` is `mismatch`. */\n mismatches: FiscalCodeMismatch[];\n hints: FiscalCodeHint[];\n /** The date of birth the code itself encodes (YYYY-MM-DD). */\n birth_date: string | null;\n /** The birth country the code itself encodes, ISO 3166-1 alpha-2 (`IT` for a comune). */\n birth_country: string | null;\n}\n\nexport interface CardKeys {\n keys: Array<{ kty: string; crv: string; x: string; kid: string; use: string; alg: string }>;\n}\n\n// ---- client (server-side) surface ---------------------------------------------------------------------\n\n// ---- server-side signup + enrolment (client scopes identity:signup / enroll:write) ---------------------\n\n/** A person your system registers on Vimine (`POST /v1/signup`). */\nexport interface SignupInput {\n email: string;\n first_name: string;\n last_name: string;\n phone?: string | null;\n /** YYYY-MM-DD */\n dob?: string | null;\n /** Demographic only: it is not cross-checked. */\n gender?: 'M' | 'F' | null;\n /** Comune (born in Italy) or city, free text (born abroad). */\n birthplace?: string | null;\n /** ISO 3166-1 alpha-2. Send it for a person born abroad: their fiscal code encodes only the state. */\n birth_country?: string | null;\n /** Validated and cross-checked against the other fields when present. */\n codicefiscale?: string | null;\n /** The person confirms a code that disagrees with their particulars (422 `codicefiscale_mismatch` with `confirmable: true`). */\n codicefiscale_confirmed?: boolean;\n /** The account terms (`platform_terms`) the person accepted on your site — optional; when given it must name the in-force version (`GET /v1/legal/platform_terms`). */\n accept_terms?: LegalRef;\n /** The platform privacy notice (`platform_privacy`) the person read on your site — optional, same rule. */\n acknowledge_privacy?: LegalRef;\n /**\n * The language of the page the person filled in. It decides the language of the mails that follow and becomes the\n * preference of a NEW account; an existing account keeps its own.\n */\n locale?: Locale | string;\n}\n\n/** Whether an association collects its members' address (`GET /v1/aps/{slug}` → `aps.member_address`). */\nexport type MemberAddressPolicy = 'none' | 'optional' | 'required';\n\n/** A member's address, as `POST /v1/enroll`, `POST /v1/me/membership` and `POST /v1/enroll/confirm` take it. */\nexport interface MemberAddress {\n /** `residence` (the default) or, where different, `domicile`. */\n kind?: 'residence' | 'domicile';\n /** Street and number. */\n line: string;\n postal_code?: string | null;\n city: string;\n /** Italian addresses only (two letters); dropped abroad. */\n province?: string | null;\n /** ISO 3166-1 alpha-2 (default `IT`). */\n country?: string;\n}\n\n/**\n * `POST /v1/enroll/confirm` after a 409 `identification_required`: what the account still lacks — a fiscal code, or\n * date, place and country of birth. It completes the EMPTY fields of the profile, never over what is there.\n */\nexport interface EnrollIdentification {\n /** YYYY-MM-DD */\n dob?: string;\n birthplace?: string;\n /** ISO 3166-1 alpha-2 */\n birth_country?: string;\n codicefiscale?: string;\n codicefiscale_confirmed?: boolean;\n}\n\n/** A published legal text named by version (and hash when published). */\nexport interface LegalRef {\n version: string;\n sha256?: string;\n}\n\n/** A membership request your system submits for a person (`POST /v1/enroll`). */\nexport interface EnrollInput extends SignupInput {\n /**\n * Optional. A person is identified by a fiscal code OR by `dob` + `birthplace` + `birth_country` — never neither\n * (422 `required` on each missing particular). When present it is validated and cross-checked against the names,\n * the date and the place (the state, for people born abroad).\n */\n codicefiscale?: string | null;\n /**\n * Residence or, where different, domicile. Asked of every member or of nobody: the public profile says what the\n * association declared (`aps.member_address`).\n */\n address?: MemberAddress;\n /** Membership type uid; optional when the association offers exactly one. */\n membership_type?: string;\n /** The in-force statuto the person accepted on your site (see `Statuto.version`; `sha256` when published). */\n accept_statuto: { version: number; sha256?: string };\n /**\n * The association's privacy notice the person read on your site (`ApsPublicConfig.privacy_notice`). REQUIRED when the\n * association publishes one; 422 `privacy_notice_outdated` when it is not the in-force version.\n */\n privacy_notice?: { version: number; sha256?: string; locale?: Locale | string };\n}\n\n/** One acceptance, acknowledgement or consent the person recorded (`GET /v1/me/acceptances`). */\nexport interface AcceptanceRecord {\n at: string;\n action: 'accepted' | 'acknowledged' | 'consented' | 'withdrawn' | 'declared';\n channel: 'ui' | 'public' | 'api' | 'job' | 'paper';\n kind: string;\n title: string;\n version: string;\n sha256: string | null;\n /** Hash of the text actually shown. */\n rendered_sha256: string | null;\n locale: string | null;\n /** The association the act concerns, when any. */\n association: string | null;\n}\n\n/** A document the person has not acted on at its in-force version. */\nexport interface PendingDocument {\n kind: string;\n title: string;\n locale: string;\n version: string | number;\n sha256: string | null;\n effective_from: string | null;\n /** What the person is asked to do. */\n action: 'accepted' | 'acknowledged' | 'consented';\n /** Never acted on any version of this kind (false: a new version requires it again). */\n first: boolean;\n}\n\nexport interface MyAcceptances {\n items: AcceptanceRecord[];\n pending: {\n /** Account-layer documents still to accept / acknowledge. */\n platform: PendingDocument[];\n /** This association's notice to members, when not yet acknowledged. */\n privacy_notice: PendingDocument | null;\n };\n}\n\n/** `POST /v1/me/acceptances`: the in-force version your app showed. */\nexport interface AcceptanceInput {\n /** `platform_terms` | `platform_privacy` | `network_consent` | `privacy_notice` */\n kind: string;\n version: string | number;\n sha256?: string;\n}\n\nexport interface AcceptanceResult {\n recorded: true;\n kind: string;\n action: string;\n version: string;\n at: string;\n}\n\n/** The uniform answer of the creating routes: whatever happened behind the address, it was accepted. */\nexport interface Accepted {\n status: 'accepted';\n}\n\n/** `POST /v1/enroll/confirm` — the outcome of the confirmation link an existing account's owner uses. */\nexport interface EnrollConfirmResult {\n status: MembershipStatus;\n /** The person already had a membership request or membership here; nothing new was created. */\n already: boolean;\n /** In order: the association's approval first (board model), then the fee. */\n pending_reasons: PendingReason[];\n payment_open: boolean;\n valid_from: string | null;\n association: { name: string; slug: string };\n /**\n * Only for a link sent by the association's hosted enrolment page when that page was opened from one of its public\n * events: what became of the place asked for together with the request. `null` for every other link.\n */\n event?: EnrolledPlace | null;\n}\n\n/** The place asked for with a membership request made from an event's page (`EnrollConfirmResult.event`). */\nexport interface EnrolledPlace {\n slug: string;\n title: string;\n starts_at: string;\n timezone: string;\n place: string | null;\n registration_type: { uid: string; name: string; amount: number; currency: string };\n /**\n * `confirmed`: the place is theirs. `reserved`: held, see `waiting`. `held`: the membership request itself still\n * waits for the address to be confirmed, and no place was asked for. `unavailable`: no place, see `reasons`.\n */\n state: 'confirmed' | 'reserved' | 'held' | 'unavailable';\n /** What a `reserved` place waits for: the membership to become active, the contribution, or both. */\n waiting: ('membership' | 'contribution')[];\n /** Why the place is `unavailable`: the reasons of the eligibility endpoint. */\n reasons: string[];\n reserved_until: string | null;\n /** How to pay a contribution that is owed, in the association's words. */\n payment_instructions: string | null;\n /** The person held this place before the link was used. */\n already: boolean;\n}\n\n/** `POST /v1/me/membership/renew` — renewed at once (free type, no approval gate) or turned into a request. */\nexport interface RenewResult {\n renewed: boolean;\n requested: boolean;\n status: MembershipStatus;\n expires_at: string | null;\n renewal_requested_at: string | null;\n}\n\n/** `PATCH /v1/me/membership/network-opt-in` */\nexport interface NetworkOptIn {\n network_opt_in: boolean;\n network_opt_in_at: string | null;\n}\n\n/** `POST /v1/checkins` — a door check-in from a scanned card token. No personal data. */\n/** `POST /v1/checkins` for a CARD token. */\nexport interface CardCheckinResult {\n kind: 'card';\n verdict: MembershipVerdict;\n status: MembershipStatus;\n membership_id: string;\n valid_until: string | null;\n /** With `verdict: 'not_yet_valid'`: when the card becomes usable. The scan is recorded all the same. */\n valid_from: string | null;\n /**\n * A note for whoever staffs the gate, never part of `verdict`: it restricts nothing. `pending`: the member has no\n * verifiable fiscal code and nobody of the association has looked at a document yet — show it. Cleared from the\n * association's console. `null`: nothing to check. The public `verifyCard` never carries it.\n */\n identity_check: IdentityCheck | null;\n checked_in_at: string;\n}\n/**\n * The identity check at first presence (`CardCheckinResult.identity_check`). `pending`: a document is still to be\n * looked at; `verified`: somebody of the association looked at one; `flagged`: somebody did, and it did not agree —\n * a matter for the association's office, which revokes nothing by itself.\n */\nexport type IdentityCheck = 'pending' | 'verified' | 'flagged';\nexport type RegistrationCheckinVerdict = 'valid' | 'already_checked_in' | 'not_confirmed' | 'cancelled' | 'event_cancelled' | 'membership_invalid';\n/** `POST /v1/checkins` for an event REGISTRATION token (`k:'reg'` in the payload). */\nexport interface RegistrationCheckinResult {\n kind: 'registration';\n verdict: RegistrationCheckinVerdict;\n status: RegistrationStatus;\n registration_id: string;\n event: { slug: string; title: string; starts_at: string };\n registration_type: string | null;\n membership_id: string | null;\n membership_verdict: MembershipVerdict | null;\n /** True the first time this registration is checked in. */\n first: boolean;\n checked_in_at: string | null;\n}\nexport type CheckinResult = CardCheckinResult | RegistrationCheckinResult;\n\n/** One row of `GET /v1/memberships` — ids and status only. */\nexport interface MembershipListItem {\n id: string;\n status: MembershipStatus;\n verdict: MembershipVerdict;\n membership_type: { cod: string } | null;\n issued_at: string | null;\n valid_until: string | null;\n updated_at: string;\n}\nexport interface MembershipList {\n items: MembershipListItem[];\n next_cursor: string | null;\n}\nexport interface MembershipListParams {\n status?: MembershipStatus;\n /** RFC 3339: only rows changed after this instant (incremental sync). */\n updated_since?: string;\n limit?: number;\n cursor?: string;\n}\n\nexport interface MembershipStatusInfo {\n id: string;\n status: MembershipStatus;\n verdict: MembershipVerdict;\n valid_until: string | null;\n membership_type: { cod: string } | null;\n}\n\nexport interface SandboxMember {\n email: string;\n name: string;\n status: MembershipStatus;\n expires_at: string | null;\n statuto_accepted: boolean;\n}\n\nexport interface SandboxMembers {\n slug: string;\n members: SandboxMember[];\n}\n\nexport interface SandboxReset {\n /** The synthetic members' shared password — shown only here. */\n password: string;\n members: Array<Pick<SandboxMember, 'email' | 'name' | 'status'>>;\n}\n\n// ---- events & registrations (/v1/aps/{slug}/events, /v1/events*, /v1/me/registrations*) ---------------------\n// Vocabulary: registration (iscrizione) and contribution (contributo) — never \"ticket\".\n\nexport type EventStatus = 'published' | 'completed' | 'cancelled';\nexport type EventVisibility = 'members_only' | 'public';\nexport type RegistrationStatus = 'reserved' | 'confirmed' | 'cancelled' | 'refunded';\n/** Why a registration was cancelled. */\nexport type RegistrationCancelReason =\n /** The member cancelled it, inside the event's cancellation window. */\n | 'user'\n /** The association's secretariat cancelled it. */\n | 'staff'\n /** A reserved place whose contribution did not arrive before the hold ran out. */\n | 'expired'\n | 'event_cancelled'\n /** A place held while the membership request was pending, for an event that starts before the new card is usable. */\n | 'card_not_valid_yet'\n /** The association did not accept the membership request (or the provisional admission) the place was held under. */\n | 'membership_rejected'\n /** The association revoked the membership the place needed. */\n | 'membership_revoked';\n/** Why a registration type is not open right now. */\nexport type RegistrationTypeReason = 'sold_out' | 'registration_not_open' | 'registration_closed';\n/** Why the member may not register (`GET /v1/events/{slug}/eligibility`, `422 not_eligible`). */\nexport type EligibilityReason =\n | 'membership_required'\n | 'membership_not_active'\n /** The event starts before the member's card is usable (the association's usability delay). */\n | 'membership_not_yet_valid'\n | 'membership_type_not_allowed'\n | 'sold_out'\n | 'event_full'\n | 'registration_not_open'\n | 'registration_closed'\n | 'max_per_user'\n | 'event_past'\n | 'event_cancelled'\n | 'event_not_published'\n | 'plan_limit'\n | 'invalid_type';\n\nexport interface EventLocation {\n name: string | null;\n address: string | null;\n lat: number | null;\n lng: number | null;\n}\n\n/** An admission class of an event: free (`amount` 0) or a contribution; places and window are live. */\nexport interface RegistrationType {\n uid: string;\n cod: string;\n name: string;\n description: string | null;\n amount: number;\n currency: string;\n quantity: number | null;\n /** Places left (never who holds them); null = unlimited. */\n remaining: number | null;\n max_per_user: number;\n requires_active_membership: boolean;\n open: boolean;\n reason: RegistrationTypeReason | null;\n opens_at: string | null;\n closes_at: string | null;\n}\n\n/** An event as the API describes it: headless copy, dates, place, images, live availability per type. */\nexport interface Event {\n id: string;\n slug: string;\n /**\n * The language the `title` was served in. When it is not the one you asked for, the association wrote no\n * translation: you got its own text — never a machine translation. Each text falls back on its own.\n */\n locale: Locale;\n /** The languages in which this event has a title. */\n locales: Locale[];\n title: string;\n summary: string | null;\n /** Markdown — render it yourself. */\n description_md: string | null;\n starts_at: string;\n ends_at: string | null;\n timezone: string;\n status: EventStatus;\n visibility: EventVisibility;\n location: EventLocation | null;\n cover_url: string | null;\n gallery: { url: string; alt: string | null; order: number }[];\n links: { label: string; url: string }[];\n registration: { opens_at: string | null; closes_at: string | null; capacity: number | null; remaining: number | null; cancellation_hours: number };\n registration_types: RegistrationType[];\n published_at: string | null;\n cancelled_at: string | null;\n cancel_reason: string | null;\n}\nexport interface EventList {\n items: Event[];\n}\nexport interface EventListParams extends LocaleParam {\n /** `upcoming` (default) | `past` | `cancelled` | `all` */\n filter?: 'upcoming' | 'past' | 'cancelled' | 'all';\n /** RFC 3339 bounds on `starts_at`. */\n from?: string;\n to?: string;\n limit?: number;\n}\n\nexport interface Eligibility {\n can_register: boolean;\n membership_verdict: MembershipVerdict | null;\n types: { uid: string; cod: string; can_register: boolean; reasons: EligibilityReason[]; pending_membership: boolean }[];\n}\n\nexport interface RegistrationRequest {\n registration_type: string;\n note?: string | null;\n quantity?: number;\n /** The language the registration was made in: the fallback for a member who never chose one. */\n locale?: Locale | string;\n}\n\n/** A person's registration (the member's own, or a guest's after the confirmation link). */\nexport interface Registration {\n id: string;\n status: RegistrationStatus;\n event: { id: string; slug: string; title: string; starts_at: string; ends_at: string | null; timezone: string; status: EventStatus; location: string | null; cancel_reason: string | null } | null;\n registration_type: { uid: string; cod: string; name: string; amount: number; currency: string } | null;\n quantity: number;\n reserved_until: string | null;\n checked_in_at: string | null;\n cancelled_at: string | null;\n cancel_reason: RegistrationCancelReason | null;\n can_cancel: boolean;\n payment: { status: 'recorded' | 'refunded' | 'void'; amount: number; currency: string; method: string; paid_at: string } | null;\n /** How to pay the contribution while `reserved` (the association's own text). */\n payment_instructions?: string | null;\n note: string | null;\n created_at: string;\n /** The registration QR payload (`vmt_…`), confirmed registrations only — draw it as a QR code. */\n token?: string | null;\n}\nexport interface RegistrationList {\n items: Registration[];\n}\n\n/** `POST /v1/events/{slug}/registrations/guest` (client scope `registrations:write`, public events only). */\nexport interface GuestRegistrationRequest {\n email: string;\n first_name: string;\n last_name: string;\n registration_type: string;\n note?: string | null;\n /** The language the registration was made in — for a guest, the language of every mail they receive. */\n locale?: Locale | string;\n}\n\n/** One row of `GET /v1/events/{slug}/registrations` — no personal data. */\nexport interface RegistrationListItem {\n id: string;\n status: RegistrationStatus;\n registration_type: string | null;\n membership_id: string | null;\n quantity: number;\n checked_in_at: string | null;\n created_at: string;\n}\nexport interface EventRegistrationList {\n items: RegistrationListItem[];\n next_cursor: string | null;\n}\nexport interface EventRegistrationListParams {\n status?: RegistrationStatus;\n limit?: number;\n cursor?: string;\n}\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vimine/sdk",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Sign in with Vimine and the Vimine API, for websites and apps of associations on vimine.network.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://developers.vimine.network/",
@@ -28,11 +28,13 @@
28
28
  },
29
29
  "files": [
30
30
  "dist",
31
- "README.md"
31
+ "README.md",
32
+ "CHANGELOG.md"
32
33
  ],
33
34
  "scripts": {
34
35
  "build": "tsc -p tsconfig.json",
35
36
  "test": "npm run build && node --test \"test/**/*.test.mjs\"",
37
+ "version": "node ../../scripts/news.mjs --write",
36
38
  "prepublishOnly": "npm run build"
37
39
  },
38
40
  "peerDependencies": {