dids: phone numbers, destinations, inbound dialplan, Phone numbers page
DIDs CRUD (any input format, normalized; 409 on duplicates; a number
that is an emergency or default caller ID can't be removed). Shared
destination service: assertDestinationExists, describeDestination
("Ring Dan Doe (101)") and findReferences over every destination
column in 02 §1 plus the unmatched-number setting; deleting an
extension a destination points at is now a 409 naming the places.
Generator: destApp (user, external, hangup for now), sp-from-trunk-*
per enabled trunk, sp-did-exists (left out when empty) and sp-inbound
with caller-name prefix. Golden case voipms-basic. Phone numbers page
with a minimal DestinationPicker (user, outside number, hang up).
trunk-test.ts: the fake provider calls the DID with a 10-digit
Request-URI like voip.ms; baresip 101 answers, caller ID arrives
normalized, 500 packets each way on both legs. scripts/e2e/m3-t2.mjs
checks the UI → Asterisk path. Still to do with real voip.ms: the
mobile-to-DID call and recording which header carries the DID (06 §3).
Task: M3-T2
This commit is contained in:
1 parent
1b7f60b5f2
commit
c117d8bb1d
28 files changed
+1371
-21
No files matched your search
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Phone numbers (DIDs) as the API accepts and returns them (02, 04 §7.3, 05 §2).
|
||||
import { z } from 'zod';
|
||||
import { DestinationSchema } from './destination.ts';
|
||||
import { normalizeNumber } from './phone.ts';
|
||||
|
||||
/** Any way of writing a number → its normalized digits (00 §8). */
|
||||
export const DidNumber = z
|
||||
.string()
|
||||
.trim()
|
||||
.transform((v, ctx) => {
|
||||
try {
|
||||
const n = normalizeNumber(v);
|
||||
if (/^\d{7,15}$/.test(n)) return n;
|
||||
} catch {
|
||||
// reported below
|
||||
}
|
||||
ctx.addIssue({ code: 'custom', message: 'A phone number like (312) 555-1234' });
|
||||
return z.NEVER;
|
||||
});
|
||||
|
||||
const DidFields = z.object({
|
||||
number: DidNumber,
|
||||
trunkId: z.uuid('Pick a trunk'),
|
||||
label: z.string().trim().max(60).nullable(),
|
||||
destination: DestinationSchema,
|
||||
callerIdNamePrefix: z
|
||||
.string()
|
||||
.trim()
|
||||
.max(12)
|
||||
.regex(/^[A-Za-z0-9 :_.#-]*$/, 'Letters, digits, spaces and : _ . # - only')
|
||||
.nullable(),
|
||||
e911Address: z.string().trim().max(200).nullable(),
|
||||
});
|
||||
|
||||
export const DidCreateSchema = DidFields.partial().required({
|
||||
number: true,
|
||||
trunkId: true,
|
||||
destination: true,
|
||||
});
|
||||
export const DidUpdateSchema = DidFields.partial();
|
||||
|
||||
export type DidCreate = z.input<typeof DidCreateSchema>;
|
||||
export type DidUpdate = z.input<typeof DidUpdateSchema>;
|
||||
|
||||
export type DidDto = z.output<typeof DidFields> & {
|
||||
id: string;
|
||||
/** "Ring Dan Doe (101)", for lists. */
|
||||
destinationSummary: string;
|
||||
createdAt: string;
|
||||
};
|
||||
@@ -8,3 +8,4 @@ export * from './users.ts';
|
||||
export * from './extensions.ts';
|
||||
export * from './live.ts';
|
||||
export * from './trunks.ts';
|
||||
export * from './dids.ts';
|
||||
Reference in new issue
Block a user